What is the rule of thumb for using #property(copy) vs. #property(retain)? - objective-c

I wonder if there is a rule of thumb you follow, when deciding whether or not a given property in ObjectiveC should be a retain or copy?
How do you decide which it should be?

Typically you use copy for safety with classes which have mutable variants, like NSString, NSArray, the other collection classes, etc. To see why, consider what happens here...
Once upon a time,
#interface MyClass : NSObject
#property (retain) NSString *happyString;
- (void)rejoice;
#end
Then one day,
- (void)bigBadMethod {
MyClass *myObject = [[[MyClass alloc] init] autorelease];
NSMutableString *theString = [NSMutableString stringWithString:#"I'm happy!"];
myObject.happyString = theString; // this is allowed because NSMutableString inherits from NSString
[myObject rejoice]; // prints "I'm happy!"
when suddenly...
[theString setString:#"BRAAAAIIINNNSSSSS"];
[myObject rejoice]; // prints "BRAAAAIIINNNSSSSS"
}
And you wouldn't want that, would you? So use #property (copy) if you don't want to get mutated while you're not looking!

In a nutshell, assign vs retain vs copy determines how the synthesized accessors interact with the Objective-C memory management scheme:
assign is the default and simply performs a variable assignment
retain specifies the new value should be sent -retain on assignment and the old value sent release
copy specifies the new value should be sent -copy on assignment and the old value sent release.
Remember that retain is done on the created object (it increases the reference count) whereas copy creates a new object. The difference, then, is whether you want to add another retain to the object or create an entirely new object.

Related

NSArray and NSMutable Array. Type of property and type of ivar are not the same

I'm working through the big nerd ranch guide for Objective-C programming.
There is an example and challenge in chapter 21 that I've been stumped on. (I actually finished the challenge but I used previous code from an example) I'd like to actually understand what I did.
It has to do with declaring a property of type NSArray and then declaring the setter method to be of type NSMutableArray. Can anyone tell me what is going on here? What happens "behind the scenes" with this statement.
#property (nonatomic copy) NSArray *assets
and what is happening in these two files? Please explain at the lowest-level possible. Thanks!
BNREmployee.h
#interface BNREmployee: BNRPerson
{
NSMutableArray *_assets
}
#property (nonatomic copy) NSArray *assets
#end
BNREmployee.m
#implementation BNREmployee
- (void)setAssets:(NSArray *)a
{
_assets = [a mutableCopy]; //What did this actually do?
}
- (NSArray *)assets
{
return [_assets copy];
}
An NSMutableArray IS an NSArray (it is a subclass), so it just gets assigned normally. Nothing special happens behind the scenes.
An example I can give looking at your models would be assigning a BNREmployee object to a BNRPerson pointer which will work fine.
BNREmployee *employee = [BNREmployee new]; // or whatever initializer
BNRPerson *person = employee; // works fine, an employee IS a person
You can always assign an NSMutableArray to an NSArray pointer, but not the other way around.
Edit
"The property has type NSArray, which tells other classes, If you ask
for my assets, you are going to get something that is not mutable.
However, behind the scenes, the assets array is actually an instance
of NSMutableArray so that you can add and remove items in BNREmployee"
By exposing the public property as an immutable type you are letting any potential callers know that they can't modify the property without explicitly calling the mutator on the object. It also lets callers know once they get the collection, its contents will never be changed out from under them. This is the standard contract when exposing an immutable property. As pointed out in one of the comments below, there can be cases where a return type is immutable but the underlying object is actually mutable internally and can change, so good practice would be to make a copy when receiving the object if you are not already receiving an actual immutable copy, such as in the case of [NSView subviews].
Making the actual underlying variable a mutable type acts as a convenience to allow the owning class to modify it internally easily. Functionally, you could accomplish the same thing by making it a regular NSArray and constantly recreating it whenever you want to change its contents (such as array = [array arrayByAddingObject:object]). This will of course be slower than just modifying a mutable instance.

Clarification on when to release pointers after allocating

In my last question (here), I had an issue where I was getting an EXC_BAD_ACCESS because I was releasing the variable I had just allocated:
NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
[s release];
should have been
NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
However, stack is a retained property of my class. It's declared like so:
#interface StateStack ()
#property (nonatomic, retain) NSMutableArray* stack;
#end
I was under the impression that when you assign a 'retain' variable, it automatically increments the retainCount of the object. So you are supposed to start by releasing your pointer (as here).
Why are these two cases different? Thanks!
Because you had to assign the property, not the instance variable. When you assign to the property it's going to retain the variable again and then you're not going to have the issue. Here's how your code should have been:
NSMutableArray* s = [[NSMutableArray alloc] init];
self.stack = s;
[s release];
This way you're not assigning to the variable, but using the property (that's, in fact, a method). If you did not release in this case then you'd have a memory leak in your code.
When you did stack = s you assigned directly to the instance variable and the array was never retained.
There is no such thing as a "retain variable". It's a retain property — meaning the setter method behind the property retains the new value and releases the old one. But assigning to a variable just assigns. In fact, the reason people generally recommend assigning directly to the instance variable in init is specifically so that it doesn't go through the setter, because the setter could conceivably have side effects you don't want in init (when your object isn't fully constructed yet).
Note: I'm talking about normal memory-management rules here. This is all different if you're using ARC. But I assume you would have mentioned if you were.
self.stack and stack are two completely different things. When you use stack, you are accessing an instance variable, not a property. This means that your accessor methods aren't called, which means automatic memory management isn't used. This is why you shouldn't release s in your example.
If you used self.stack instead, then you would be using a property. The compiler will treat self.stack = value exactly the same as [self setStack:value], and self.stack the same as [self stack]. Since accessors are being used, memory management will be taken care of to match the way you defined your property, and you should release a value after assigning it.
Maurício has the right answer: be sure to assign to the property to gain the benefits of #property. To clarify the point somewhat, try using code like this:
#interface StateStack : NSObject {
NSArray *_stack;
}
#property (nonatomic,retain) NSMutableArray *stack;
#end
#implementation StateStack
#synthesize stack=_stack;
#end
Now, if you try:
NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
[s release];
You'll get an error, which will mean you tried to set the ivar rather than the property as intended. This mismatch between ivar name and property name is against Apple's recommendations, but it's a fine way to help you develop the habit of using property assignment when you intend to do so.

Objective-C, interface declarations with properties

In the following common sample,
////
#interface MyObject : NSObject
{
#public
NSString * myString_;
}
#property (assign) NSString * myString;
#end
#implementation MyObject
#synthesize myString = myString_;
#end
////
why declare myString_ in the interface at all?
I ask because we can still get and set myString in the implementation using self.myString, [self myString], self.myString = ... and [self setMyString:...] and in fact we must if instead it's being retained.
This is a matter of preference/convention for some. By default, doing:
#property (assign) NSString * myString;
...followed by:
#synthesize myString;
...will give you three things. You get a setter method that can be accessed as self.myString = #"newValue" or [self setMyString:#"newValue"], a getter method that can be accessed as NSString* temp = self.myString or NSString* temp = [self myString], and an instance variable named myString that be be accessed directly inside of your class (i.e. without going through the getter and setter) and used to set and get the property value, and which is used internally to back the property.
If you like you can do #synthesize myString = someOtherVarName, and then you still get the setters and getters just as before, but instead of the myString instance variable the someOtherVarName instance variable is used to back the property, and no myString variable is created.
So why ever use the more verbose syntax? There is never any case that requires that you do so, but some people prefer to do so when dealing with properties that are declared retain or copy. The reason for this being that setting a property declared retain or copy via its generated setter method will affect the retain-count of the object being set/unset. Doing the same thing by accessing the instance variable directly will not.
So by aliasing the instance variable to something else, you can make a distinction in the code along the lines of "anything that does xxx.myString = Y is modifying the retain count, while anything that does someOtherVarName = Y is not". Again, it's not necessary to do this, but some people prefer to.
You should be able to skip it. Modern compilers allow that.
When you define a property, you are actually declaring how the getter and setter methods are constructed for a particular instance variable. Earlier it needed the instance variable to be defined so you declared it. It also allowed the property name to differ from the instance variable name via #synthesize myProperty = myIVar;. Now you don't need to do this as the modern compilers generate the instance variable for you.
The dot syntax is actually a convenience thing as you would've noticed. It doesn't directly refer to the instance variable but the methods myProperty and setMyProperty:. You can even call myArray.count where count isn't a property (I wouldn't recommend it even though lot of people seem to like it).
While there is a difference between the two, the gap seems to be slowly closing.
That's just a problem about point of view. If you access ivar directly, it's you're accessing it internally. If you're using property, you're not accessing ivar (semantically). You're using accessing method of the object. So you're handling the self as like external object which the internal is unknown.
This is encapsulation problem of Object-Oriented paradigm.
And I recommend some tricks when using properties.
The ivar declaration is optional, not required. Compiler will generate it automatically.
You should set the ivar as #protected or #private to encapsulate it correctly. (at least there is no reasonable reason)
I recommend to use nonatomic if you don't need threading lock when accessing the property. Threading lock will decrease performance greatly, and may cause strange behavior in concurrent execution code.
You can use this code to do same thing.
#interface MyObject : NSObject
#property (assign,nonatomic) NSString * myString;
#end
#implementation MyObject
#synthesize myString;
#end
And this will be transformed roughly something like this.
#interface MyObject : NSObject
{
#private
NSString* myString; // Ivar generated automatically by compiler
}
#end
#implementation MyObject
// Methods with thread synchronization locking generated automatically by compiler.
- (NSString*)myString { #synchronized(self) { return myString; } }
- (void)setMyString:(NSString*)newMyString { #synchronized(self){ myString = newMyString; } }
#end
In fact, I'm not sure about synchronization lock with assign behavior directive, but it's always better setting it nonatomic explicitly. Compiler may optimize it with atomic operation instruction instead of locking.
Here is reference document about the properties: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html%23//apple_ref/doc/uid/TP30001163-CH17
With the modern Obj-C runtime, declaring the ivar is more of a formality than anything else. However, there are some memory management things to keep in mind.
First, the property declaration for an object type is usually retain, or for strings it may be copy. In either case, the new object is retained.
Given the following code:
NSString *string = [[NSString alloc] init];
myString_ = string;
self.myString = string; // If the property was retain or copy
The second assignment would leak; the first would not. This is because the property would retain something that already has a retain count of 1—it is now at 2. When you release the property in dealloc, the count goes to 1, not 0, so it won't be released. With the first option, however, the retain count stays at 1, so dealloc brings it down to 0.
In your example, leaving the property as assign will make the ivar declaration a formality.

What happens to a property if its value is overwritten?

Lets suppose I created a property tempStr that is of NSString type.
I synthesized it obviously.
In one of my methods, I set the value of tempstr to be yellowcolor.
Then just after that I reinitialized tempStr with redcolor.
So I wanna know what happens to the memory of tempStr in this case.
Thanx.
It depends on what attribute you set for your property: retain, assign or copy.
#property (retain) NSString *tempStr: the old value (yellowcolor) would be released and the new value (redcolor) would be retained. The only exception is when yellowcolor == redcolor. Then nothing would happen, because old and new values are the same.
#property (assign) NSString *tempStr: there would be no release/retain operations. It is equal to changing just a pointer. So after this operations yellowcolor won't be released and you'll lost a reference to it (if there is no other reference to it in your code). So it can cause a memory leak.
#property (copy) NSString *tempStr: it's similar to retain but it call copy on new value instead of just retain, so it'd create a duplicate object in a memory. Considering NSString, it's equal to retain, because NSString is immutable, so there is no need to make a duplicate.
You can find some code examples here.
EDIT: As #Bavarious mentioned, copy is equal to retain only if you initialize this property with NSString. It won't be equal if you initialize it with NSMutableString, because this one is mutable, so the "proper" copy would be make.
A synthesized setter looks a bit like this:
- (void)setSomeString:(NSString *)newString
{
if ([newString isEqualToString:someString]) return;
[someString autorelease];
someString = [newString copy]; // or [newString retain], depends how you defined the property ...
}
So the old value is released when the new value is assigned to the pointer.

Objective-C memory management: Inside the `setMyArray` method, is it necessary to release `myArray` before setting a new value to it?

The following code is on Apple's website.
1) Inside the setMyArray method, is it necessary to release myArray before setting a new value to it? I thought setting the value of an object to a new object, will release the old object from memory.
2) Why does it say myArray = [newArray mutableCopy];, instead of simply saying myArray = newArray;? Is it necessary to pass a mutable copy to our property?
#interface MyClass : NSObject {
NSMutableArray *myArray;
}
#property (nonatomic, copy) NSMutableArray *myArray;
#end
#implementation MyClass
#synthesize myArray;
- (void)setMyArray:(NSMutableArray *)newArray {
if (myArray != newArray) {
[myArray release];
myArray = [newArray mutableCopy];
}
}
#end
EDIT:
Would it be the same if myArray was (nonatomic, retain)
Apple Documentation
copy
Specifies that a copy of the object should be used for assignment. (The default is assign.)
**The previous value is sent a release message**.
With respect to #1, yes you must release myArray before setting a new value to it, otherwise you'll leak. Note the property, it's labelled as a copy, meaning that myArray will hold an object with a reference count of one once its set.
And with regards to #2, because if you don't mutableCopy, you're not getting a copy of the object, you're simply pointing at the other thing. So, if the other thing goes away, you'll have a pointer to a dangling object. Bad things ensue from that point forward.
1 - In order to avoid a memory leak you must release the array before setting a new value to it.
2 - mutableCopy is required in the context you provided in order to geta copy of the object, and not just a pointer. If the original array goes away, you'd be left with a dirty pointer.
FYI, copies in Objective-C are shallow, not deep copies. This means that when you do [array copy] or [array mutableCopy], you get an array which is separate from the original array, but which still points to all the same objects. If you want to perform a deeper copy, you'll have to do it manually, for example by iterating through the original array, making copies of the contents, and adding those copies to a new array.