Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IOS: Release for NSString is not working as expected

I found a strange behavior with NSString. I tried to run the below code and noticed this.

NSString *str = [[NSString alloc] initwithstring : @"hello"];
[str release];
NSLog(@" Print the value : %@", str);

Here, in the third line app should crash because we are accessing an object which is released. But it is printing the value of str. It is not crashing. But with NSArray i observed different behavior.

NSArray *array = [[NSArray alloc] initwithobjects : @"1",  @"2", nil];
[array release];
NSLog(@"Print : %@", [array objectatindex : 0]);
NSLog(@"Print : %@", [array objectatindex : 0]);

The code has two NSLog statements used for NSArray. Here after releasing when the first NSLog is executed, it is printing value. But when second NSLog is executed, app crashes. App crash is acceptable because the array accessed was released already. But it should crash when the first NSLog is executed. Not the second one.

Help me with this behaviors. How release works in these cases.

Thanks Jithen

like image 629
Coder Avatar asked Mar 01 '13 04:03

Coder


3 Answers

The first example doesn't crash because string literals are never released. The code is really:

NSString *str = @"hello";
[str release];

People get burned with string literals on memory management and mistakenly using == to compare them instead of isEqualToString:. The compiler does some optimizations that lead to misleading results.

Update:

The following code proves my point:

    NSString *literal = @"foo";
    NSString *second = [NSString stringWithString:literal];
    NSString *third = [NSString stringWithString:@"foo"]; // <-- this gives a compiler warning for being redundant
    NSLog(@"literal = %p", literal);
    NSLog(@"second = %p", second);
    NSLog(@"third = %p", third);

This code gives the following output:

2013-02-28 22:03:35.663 SelCast[85617:11303] literal = 0x359c
2013-02-28 22:03:35.666 SelCast[85617:11303] second = 0x359c
2013-02-28 22:03:35.668 SelCast[85617:11303] third = 0x359c

Notice that all three variable point to the same memory.

like image 65
rmaddy Avatar answered Nov 09 '22 04:11

rmaddy


Your second example crashes at the second NSLog because at the first log, the memory where array was hasn't been re-used, but that first log causes enough activity on the heap to cause the memory to become used by something else. Then, when you try to access it again, you get a crash.

Whenever an object is deallocated and its memory marked as free, there is going to be some period of time where that memory still stores what's left of that object. During this time you can still call methods on such objects and so forth, without crashing. This time is extremely short, and if you're running a lot of threads it may not even be enough to get your method call in. So clearly, don't rely on this implementation detail for any behavior.

As others have said, regarding your first question, NSString literals aren't going to be deallocated. This is true for some other Foundation classes (NSNumber comes to mind) but is an implementation detail as well. If you need to do experiments on memory management, use an NSObject instance instead, as it will not show the unusual behaviors.

like image 33
Carl Veazey Avatar answered Nov 09 '22 06:11

Carl Veazey


When you send a release message on an object, the object is actually not being removed from the memory. The release message simply decrements the reference count by one only. If the reference count is zero the object is marked as free. Then the system remove it from the memory. Until this deallocation happens you can access your object. Even if you release the object your object pointer still points to the object unless you are assigning nil to the pointer.

like image 4
Anil Varghese Avatar answered Nov 09 '22 06:11

Anil Varghese