Gypsa Gypsa - 2 months ago 8
Objective-C Question

IOS Release and assignment messages differences for nsstring

I was going through the memory management concepts. I created one

string1
and assign that
string1
into another
string2
, now I release this
string1
.
Here
string2
retain count is 1 but on
NSLog
statement it gives EXC Bad access.

When I am assigning the string

NSString * string1 = [[NSString alloc]initWithFormat:@"hello"];
string2 = string1;

NSLog(@"string1 memory address = %p, string2 memory address = %p", &string1, &string2);

[string1 release];

NSLog(@"[string2 retainCount] = %lu", (unsigned long)[string2 retainCount]);
NSLog(@"string2 = %@", string2); // here app is crashing


Does it means that string2 has an autorelease message also with it because if I do
string2 = [string1 copy];
instead of
string2 = string1;
it doesn't crash.
So I wanted to ask whether the crash is because it has autorelease message of
string2
and how it is relating with
string2
release command.
Please advice!

Answer

Assignment doesn't change object's retain count if you use manual memory management in Objective-C. And you for sure use it, otherwise, you can't invoke release method in your code.

So, your code does the following. It creates NSString object with retain count = 1, and assigns it to string1 pointer. After that, you assigns string1 to string2. Now you have 2 pointers to the same object, and retain count of this object is still 1. Then you release object, it deallocated immediately. And after that you experiencing crash:

NSString * string1 = [[NSString alloc]initWithFormat:@"hello"]; // string retain count is 1 
string2 = string1; // 2 pointers to same string, retain count is still 1
[string1 release]; // string is deallocated when retain count drops to 0
NSLog(@"string2 = %@", string2); // here app is crashing

To fix that, you can use retain when you do an assignment.

NSString * string1 = [[NSString alloc]initWithFormat:@"hello"]; // string retain count is 1
string2 = [string1 retain]; // 2 pointers to same string, retain count is 2
[string1 release]; // string retain count back to 1
NSLog(@"string2 = %@", string2); // no crash

Also, you can use copy. Note that for NSString copy doesn't actually copies an object, it simply invokes retain. There is no need to perform actual copying, because NSString is immutable and can't be changed. If we will use NSMutableString, things will change:

NSMutableString * string1 = [[NSMutableString alloc]initWithFormat:@"hello"]; // string retain count is 1
NSMutableString * string2 = [string1 copy]; // 2 separate strings, both have retain count 1
[string1 release]; // string1 is deallocated
NSLog(@"string2 = %@", string2); // no crash, string2 retain count is 1

Alternatively, you can use ARC. It will insert corresponding retain/release calls at compile time. Code then will look like:

NSString * string1 = [[NSString alloc]initWithFormat:@"hello"];
string2 = string1;
string1 = nil;
NSLog(@"string2 = %@", string2); // no crash

I suggest to understand manual memory management first, and after that migrate to ARC.