0

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!

Borys Verebskyi
  • 4,160
  • 6
  • 28
  • 42
Gypsa
  • 11,230
  • 6
  • 44
  • 82

1 Answers1

1

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.

Borys Verebskyi
  • 4,160
  • 6
  • 28
  • 42
  • Thanks for the detail explanation, just one doubt, string2 = string1; // 2 pointers to same string, retain count is still 1 does it means that the memory address of string 1 and string 2 will be same, because when I am printing the memory address they are different. so 2 pointers to same string, pls explain in terms of memory locations and address. Pls. – Gypsa Sep 21 '16 at 18:38
  • `string1` and `string2` are already C pointers, you don't need to take their addresses in `NSLog`. Use the following code instead `NSLog(@"string1 memory address = %p, string2 memory address = %p", string1, string2);`, and you'll see that they are pointing to the same address. – Borys Verebskyi Sep 21 '16 at 18:45
  • Thanks Boris for clarity. It helps a lot. – Gypsa Sep 21 '16 at 18:48