What happens to a property if its value is overwritten? - objective-c

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.

Related

what will happen if assign a weak property to a strong property?

In old term, it's about assign a autoreleased property to a retain property. What will happen if do that, something like the following does.
#property(strong, nonatomic) NSString *new;
...
NSString *old = [NSString stringWithFormat:#"%# %#"), #"hello", #"world"];
new = old;
adding to my comment on your question:
read this
Variable Qualifiers
It describes the different types of lifetime qualifiers you can declare variables with and gives examples of each.
Edit with relevant bits:
The lifetime qualifiers you can use are:
__strong
__weak
__unsafe_unretained
__autoreleasing
Their descriptions are in the docs but I will go into the first 2.
__strong is the default type (when you don't specify one) and it will increase the retain count of the object by 1. As long as there is a strong pointer pointing to an object, it will remain alive.
__weak does not increase the retain count of an object and will not keep it alive. If there are no strong references pointing to the same object, the weak pointer will be set to nil automatically. (__unsafe_unretained is actually almost the same as weak but they are left dangling instead of being set to nil).
If you create an object immediately assigned to a weak pointer, it will be instantly deallocated since there are no strong references to it.
Sample Code from docs:
NSString * __weak string = [[NSString alloc] initWithFormat:#"First Name: %#", [self firstName]];
NSLog(#"string: %#", string);
The value of string will be null when trying to print it in this case.
You can only use a weak pointer if the object you want to reference with it already has at least one strong reference to it. Otherwise the (new) object will be deallocated instantly.

what does it mean to declare a NSNumber variable as property copy

I am still learning ..., so for the following property
#property (copy) NSNumber *foo;
What the copy really do? make a copy of the (value of) foo and put it to new place? Just like a copy constructor?
And also to clarify, the following is basically doing a AddRef, right?
#property (retain) NSNumber *foo;
See the description of properties here:
http://cocoacast.com/?q=node/103
copy means that assigning a value into the property will make a copy of the input value.
retain means that you won't get an actual copy; you'll get the same object with an extra retain on it. So if it's modified elsewhere, you'll see the modifications in both places.
For NSNumbers, they are immutable, so copy and retain are functionally equivalent.
What the copy really do?
In general, NSNumber is immutable -- I'd expect that copy in those cases would be implemented using retain:
- (id)copyWithZone:(NSZone*)zone {
return [self retain];
}
And also to clarify, the following is basically doing a AddRef, right?
Well, synthesizing it will add the reference counting boilerplate - the actual operation is more complex and takes the generalized form:
- (void)setFoo:(NSNumber *)arg {
NSNumber * prev = foo;
foo = [arg retain]; // << or foo = [arg copy]; if you have specified 'copy'
[prev release];
}

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

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.

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.

NSMutableArray as #property with readonly

Suppose I have something like this:
#property (readonly) NSMutableArray *someArray;
Can I modify [obj someArray] even though the #property is set to readonly?
Yes, you can modify its contents. The readonly only applies to the pointer itself - in that way, it is not like C++'s const.
Basically, saying "readonly" just means "don't translate a.someArray = foo into [a setSomeArray:foo]". That is, no setter is created.
(Of course, if you wanted to prevent modification, you'd just use an NSArray instead.)
The contents of someArray are modifiable, although the property is not (i.e. a call cannot change the value of the someArray instance variable by assigning to the property). Note, this is different from the semantics of C++'s const. If you want the array to be actually read-only (i.e. unmodifiable by the reader), you need to wrap it with a custom accessor. In the #interface (assuming your someArray property)
#property (readonly) NSArray *readOnlyArray;
and in the #implementation
#dynamic readOnlyArray;
+ (NSSet*)keyPathsForValuesAffectingReadOnlyArray {
return [NSSet setWithObject:#"someArray"];
}
- (NSArray*)readOnlyArray {
return [[[self someArray] copy] autorelease];
}
Note that the caller will still be able to mutate the state of objects in the array. If you want to prevent that, you need to make them immutable on insertion or perform a depp-copy of the array in the readOnlyArray accessor.