I've just been reading a short blog post from Craig Hockenberry about ARC and copy. The question I now have is should parameters passed to initializers that are assigned to instance variables always use copy? Or does it depend on the type of the instance variable?
#import "MyObject.h"
#implementation MyObject {
SomeType *_ivar1;
SomeOtherType *_ivar2;
}
-(id)initWithParam1:(SomeType *)param1 andParam2:(SomeOtherType *)param2
{
if ((self == [super init])) {
_ivar1 = [param1 copy]; // Always good
_ivar2 = [param2 copy]; // practice?
}
return self;
}
#end
I think the key to understanding the post is in this statement:
Since I think it’s a bad idea to use accessors during -init the copy semantics defined by the #property are never used and ARC happily retains the reference instead of copying it.
I think that Craig is talking specifically about the following case:
#interface MyObject : NSObject {
SomeType *_ivar1;
}
-(id)initWithParam1:(SomeType *)param1;
#property (copy, nonatomic) SomeType* prop1;
#end
#implementation MyObject
#synthesize prop1 = _ivar1;
-(id)initWithParam1:(SomeType *)param1 {
if ((self == [super init])) {
/*
Craig could have called
self.prop1 = param1;
but he believes that it's a bad idea to call accessors
from the initializer, so he calls copy explicitly.
*/
_ivar1 = [param1 copy];
}
return self;
}
#end
Depends on the type of the variable and intent.
For simple types -- NSString, NSArray, NSNumber, etc... -- you use copy because you generally want the stored type to be immutable. I.e. it doesn't make sense to have a firstName property where something externally can modify it by passing in an instance of NSMutableString.
For more complex classes -- ones that encapsulate both state and functionality -- you generally do not want to copy it exactly because that state may be changing over time. For example, if your app were a streaming video app that had a VideoPlayer instance that played a video encapsulated in a StreamingVideo instance, you wouldn't want to copy the StreamingVideo as its internal state is constantly going to be changing as more data is downloaded (or an error occurs).
I.e. copy is used when you want an immutable snapshot of state and a reference is used when you want object A to be connected to B for purposes of changing/monitoring/querying B's state.
And, yes, you want it to be consistent. If a property is copy and you have a convenience initializer that sets that property, make sure the convenience initializer also copies whatever is set to the property.
Related
I always see people debating whether or not to use a property's setter in the -init method. My problem is how to create a default value in a subclass for an inherited property. Say we have a class called NSLawyer -- a framework class, that I can't change -- with an interface that looks like this:
#interface NSLawyer : NSObject {
#private
NSUInteger _numberOfClients;
}
#property (nonatomic, assign) NSUInteger numberOfClients;
#end
And an implementation that looks like this:
#implementation NSLawyer
- (instancetype)init
{
self = [super init];
if (self) {
_numberOfClients = 0;
}
return self;
}
#end
Now let's say I want to extend NSLawyer. My subclass will be called SeniorPartner. And since a senior partner should have lots of clients, when SeniorPartner gets initialized, I don't want the instance to start with 0; I want it to have 10. Here's SeniorPartner.m:
#implementation SeniorPartner
- (instancetype)init
{
self = [super init];
if (self) {
// Attempting to set the ivar directly will result in the compiler saying,
// "Instance variable _numberOfClients is private."
// _numberOfClients = 10; <- Can't do this.
// Thus, the only way to set it is with the mutator:
self.numberOfClients = 10;
// Or: [self setNumberOfClients:10];
}
return self;
}
#end
So what's a Objective-C newcomer to do? Well, I mean, there's only one thing I can do, and that's set the property. Unless there's something I'm missing. Any ideas, suggestions, tips, or tricks?
You should do exactly has you have; call the accessor. The declaring class typically avoids calling its own accessors in init to avoid accidentally calling an overridden accessor in a subclass that might rely on the consistency of data you haven't initialized yet. Your superclass on the other hand should be completely consistent by the time the subclass's init is run, so there is no problem using superclass accessors at that time.
Consider the common and general case: you want to set your transform in a UIView subclass. How would you solve that other than call setTransform:? Subclassing non-Apple code is no different.
Make it #protected. It is very rare to make an ivar or property private these days. Private ivars and/or properties are better declared in the implementation. For that matter #protected ivars/properties are rarely seen in Objective-C but perfectly fine.
Using a setter either as a method or with dot notation is just wrong (yes it works but is really bad form), if you want use setters/getters declare a property.
I realize that it automatically creates a setter & getter for you but I'm uncertain how the setter actually "looks".
Also, why is it recommended that we say #synthesize someObject = _someObject; instead of just #synthesize someObject;?
Easy bit first: you don't need to #synthesize at all any more. If you have an #property and you don't synthesise it then one is implied, of the form #synthesize someObject = _someObject;. If you left off the = _someObject then you would have the same thing as #synthesize someObject = someObject;. The underscore version is therefore preferred because Apple has swung back to advocating underscores for instance variables and because it's consistent with the implicit type of synthesise.
The exact form of setter and getter will depend on the atomic, strong, unsafe_unretained, etc flags but sample nonatomic strong setter, pre-ARC is:
- (void)setProperty:(NSString *)newPropertyValue
{
[newPropertyValue retain];
[_property release];
_property = newPropertyValue;
}
Note the retain always occurs before the release. Otherwise the following (which you would arrive at in a roundabout fashion rather than ever writing directly):
self.property = _property;
Would lead to _property potentially being deallocated before it was retained.
A sample getter (also pre-ARC) is:
- (NSString *)property
{
return [[property retain] autorelease];
}
The retain ensures that the return value will persist even if the object it was queried from is deallocated. The autorelease ensures you return a non-owning reference (ie, the receiver doesn't explicitly have to dispose of the thing, it can just forget about it when it's done). If the thing being returned is immutable but the instance variable is mutable then it's proper form to copy rather than retain to ensure that what you return doesn't mutate while someone else is holding onto it.
Check leture 3 of iPad and iPhone Application itunes
_someObj replace a memory location for store your object(a pointer).
Xcode 4 auto #synthesize anyObject = _anyObject; -> So you don't need to write #synthesize anymore.
If you have some other object or _anyMemoryLocation write before in your.m file, you can use #synthesize yourObj = _anyMemeryLocation if you don't want rewrite all name in your.m file.
Setter and getter 2 methods use to set or get your object's value outside or inside your class:
-(void)setObject:(ObjectType *) object;
-(void)getObject:(ObjectType *) object;
The key nonatomic auto generate setter and getter for you.
If you want to implement more method went setObject, you can rewrite it in your.m file
-(void)setObject:(ObjectType *) object{
_object = object; //rewrite setter can done anywhere in your.m file
//Add more method
}
I am using ARC.
This is my .h file
...
- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
...
This is my .m file
....
#synthesize coordinate, title;
- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t
{
self = [super init];
if (self) {
coordinate = c;
[self setTitle:t];
}
return self;
}
....
Is setting coordinate this way, the right way to do it? Given that I declare it as readonly, it seems like it is the only way to do it. What if I just use the default (i.e. readwrite), in this case, should I use the setter method [self setCoordinate] instead?
I could set the title by doing title = t as well. Compare to using the setter method, the result is the same, but what is the difference ?
Thanks! Wish I could accept all of your answers.
You're actually supposed to set ivars directly in an initializer method all the time. This is true whether or not you have a readonly or readwrite property. The documentation here even says so.
The reasoning behind this has to do with inheritance. If someone were to subclass your class and overwrite the setters for your properties such that they bypass the ivars you created (or do some other wacky thing), then suddenly your original implementation of your initializer method now no longer does what it is written to do. In particular, your initializer could end up creating an object with a weird state due to the subclass overriding your accessors. In the pre-ARC days, you could also end up with tricky (or just straight-up broken) memory situations when this sort of thing happens. The take-away message is: you should write initializers so that they will always create an object with a known valid state.
So (assuming you're using ARC) your initializer should actually be:
- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t
{
self = [super init];
if (self) {
coordinate = c;
title = [t copy];
}
return self;
}
Personally, I prefer to synthesize ivars with a starting underscore to clarify when I'm using the property and when I'm accessing the ivar directly (LLVM 4.0 now does this to automatically synthesized properties as well).
#synthesize coordinate = _coordinate;
#synthesize title = _title;
- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t
{
self = [super init];
if (self) {
_coordinate = c;
_title = [t copy];
}
return self;
}
1: As your code is now, yes, that is the right way to do it. If you weren't using ARC (assuming you are currently), you'd also want to retain the value to assert ownership. This will be done automatically under ARC. Keep in mind that that is not the only way of doing it; you could redeclare the property as readwrite in the class extension in the implementation file. This is a common practice which allows you to have the benefits of a readwrite property while having the property still be readonly to users of the class. Ex.
//MyClass.h
#interface MyClass : NSObject
#property (nonatomic, strong, readonly) NSNumber* number;
- (void) initWithNumber:(NSNumber*)number;
#end
//MyClass.m
#interface MyClass ()
#property (nonatomic, strong, readwrite) NSNumber* number;
#end
#implementation MyClass
//this changes the instance variable backing the property to _number.
#synthesize number = _number;
- (void) initWithNumber:(NSNumber*)number{
self = [super init];
if (self) {
self.number = number;
}
return self;
}
#end
At the end of the day, I'd say it's a good habit to use setters whenever you can to keep things KVO compliant and so that you always know when values change. For instance, if you have a custom UIView with a property that is reflected in its appearance, chances are you'd want to redisplay yourself when it changes. The easiest way to do this is to implement the setter yourself and call setNeedsDisplay after setting the value. You couldn't do that if you set the instance value backing the property directly; the user of the class would have to remember to call setneedsDisplay every time they set it, manually.
2: One goes through the setter method, giving you a way to know when a value is going to be set, while one sets a value to the instance variable backing the property. The setter method will always handle memory management in the way it was told to, while it's up to you to do things such as copying values for a copy setter if you assign directly to an instance variable, so that you maintain some consistent scheme. Going through setters sometimes, and not others can lead to some nasty bugs if you don't be careful. Never going through setters makes it hard to know when values change, making it near impossible to weed out invalid values. For instance, if you had an int property you wanted to limit to values in some range and someone passed in a value under the minimum limit, you'd probably want to set the property to the lowest possible value in the range. You can't do that without the value going through the setter first.
Yes, it is fine to set it like that. If you prefer to use a property all the time you can override the property to be read/write rather than read-only in a class extension. In Foo.m:
#interface Foo ()
#property (nonatomic) CLLocationCoordinate2D coordinate;
#end
#implementation Foo {
// ...
self.coordinate = c;
}
Setting the coordinate that way is correct, and is the only way to do it if you have declared the property readonly.
Setting the title using title = t is different than setting the title using [self setTitle:t]. If you directly assign to the instance variable, you will just retain the NSString instance that was passed as argument t. But if you using the accessor method, the accessor will ask the string to copy itself (because you declared the property copy). If the string you were given as argument t is actually an NSMutableString, then you will get an immutable copy of it. If the string you were given as argument t is already an immutable string, it will just return itself when asked for a copy.
self.coordinate = c;
is essentially compiled to be the same as calling
[self setCoordinate:c];
The difference between coordinate = c and [self setCoordinate:c]; is that the first is just setting a variable directly where as the second is calling a method.
The reason to be wary is that methods could potentially have side effects depending on how the implementation is written e.g. (stupid example)
- (void)setCoordinate:(CLLocationCoordinate2D)coordinate;
{
_coordinate = coordinate;
[self doSomethingCrazy];
}
What is the semantic difference between these 3 ways of using ivars and properties in Objective-C?
1.
#class MyOtherObject;
#interface MyObject {
}
#property (nonatomic, retain) MyOtherObject *otherObj;
2.
#import "MyOtherObject.h"
#interface MyObject {
MyOtherObject *otherObj;
}
#property (nonatomic, retain) MyOtherObject *otherObj;
3.
#import "MyOtherObject.h"
#interface MyObject {
MyOtherObject *otherObj;
}
Number 1 differs from the other two by forward declaring the MyOtherObject class to minimize the amount of code seen by the compiler and linker and also potentially avoid circular references. If you do it this way remember to put the #import into the .m file.
By declaring an #property, (and matching #synthesize in the .m) file, you auto-generate accessor methods with the memory semantics handled how you specify. The rule of thumb for most objects is Retain, but NSStrings, for instance should use Copy. Whereas Singletons and Delegates should usually use Assign. Hand-writing accessors is tedious and error-prone so this saves a lot of typing and dumb bugs.
Also, declaring a synthesized property lets you call an accessor method using dot notation like this:
self.otherObj = someOtherNewObject; // set it
MyOtherObject *thingee = self.otherObj; // get it
Instead of the normal, message-passing way:
[self setOtherObject:someOtherNewObject]; // set it
MyOtherObject *thingee = [self otherObj]; // get it
Behind the scenes you're really calling a method that looks like this:
- (void) setOtherObj:(MyOtherObject *)anOtherObject {
if (otherObject == anOtherObject) {
return;
}
MyOtherObject *oldOtherObject = otherObject; // keep a reference to the old value for a second
otherObject = [anOtherObject retain]; // put the new value in
[oldOtherObject release]; // let go of the old object
} // set it
…or this
- (MyOtherObject *) otherObject {
return otherObject;
} // get it
Total pain in the butt, right. Now do that for every ivar in the class. If you don't do it exactly right, you get a memory leak. Best to just let the compiler do the work.
I see that Number 1 doesn't have an ivar. Assuming that's not a typo, it's fine because the #property / #synthesize directives will declare an ivar for you as well, behind the scenes. I believe this is new for Mac OS X - Snow Leopard and iOS4.
Number 3 does not have those accessors generated so you have to write them yourself. If you want your accessor methods to have side effects, you do your standard memory management dance, as shown above, then do whatever side work you need to, inside the accessor method. If you synthesize a property as well as write your own, then your version has priority.
Did I cover everything?
Back in the old days you had ivars, and if you wanted to let some other class set or read them then you had to define a getter (i.e., -(NSString *)foo) and a setter (i.e., -(void)setFoo:(NSString *)aFoo;).
What properties give you is the setter and getter for free (almost!) along with an ivar. So when you define a property now, you can set the atomicity (do you want to allow multiple setting actions from multiple threads, for instance), as well as assign/retain/copy semantics (that is, should the setter copy the new value or just save the current value - important if another class is trying to set your string property with a mutable string which might get changed later).
This is what #synthesize does. Many people leave the ivar name the same, but you can change it when you write your synthesize statement (i.e., #synthesize foo=_foo; means make an ivar named _foo for the property foo, so if you want to read or write this property and you do not use self.foo, you will have to use _foo = ... - it just helps you catch direct references to the ivar if you wanted to only go through the setter and getter).
As of Xcode 4.6, you do not need to use the #synthesize statement - the compiler will do it automatically and by default will prepend the ivar's name with _.
I'm still learning about Objective-C memory management. I'm trying to implement several simple classes in an example program that I'm building.
As an example, say I have the following class definition:
#import <UIKit/UIKit.h>
#interface customViewController : UIViewController
{
customObject *myCustomObject;
}
#property (retain) customObject *myCustomObject;
- (void)replaceCustomObject:(customObject *)newObject;
#end
For the property, I use the standard synthesize keyword...
#synthesize myCustomObject;
Then please assume that in the instance of customViewController the myCustomObject is already set with a valid value and is in use. Then the method replaceCustomObject is defined as:
- (void)replaceCustomObject:(customObject *)newObject
{
//Does this cause a memory leak because I just assign over
//the existing property?
self.myCustomObject = newObject;
}
As the comment asks, does this leak memory? Or is this the valid way to replace a previous object with a new object?
Thank you,
Frank
As others have mentioned, your code is perfectly valid and won't leak memory when assigning to the property.
If you have forgotten to implement a proper dealloc method, the last object assigned will be leaked when your customViewController is destroyed. A proper dealloc implementation would look like so:
- (void)dealloc
{
self.myCustomObject = nil;
[super dealloc];
}
That's perfectly valid, and does not leak memory. The synthesized accessors manage retain counts correctly.
(As an aside, you don't need that replaceCustomObject: method; since your property is readwrite by default, you have an auto-generated setCustomObject: method that clients of your class can use, and which follows the normal Cocoa naming conventions.)
According to this, if you use (retain) in your declaration, the synthesized method will release the old value first, then retain the new one:
if (property != newValue) {
[property release];
property = [newValue retain];
}
the property accessor syntax
self.x = y;
has the same effect as calling the setter method explicitly:
[self setX:y];
The accessor method will do whatever it has been written to do. In your case, for a #property(retain) property that has been #synthesized, the accessor will release the old object and retain the new one.
So, calling the setter, whether explicitly or through the '.' syntax, will do the right thing - including the right memory management.
So in short: no, this will not leak memory.