Over-release an object and the app does not crash - ios

#property (retain) NSString *testString;
self.testString = [[NSString alloc] initWithString:#"aaa"];
[self.testString retain];
self.testString = [NSString stringWithString:#"a"];
[self.testString release];
[self.testString release];
Let's go line by line:
Line 2: retain count of testString = 2
Line 3: retain count of testString = 3
Line 4: retain count of testString = 1
Line 5: retain count of testString = 0
Line 6: it should crash
Even if there's other stuff holding to testString in CoreFoundation, it eventually will go away. But the app never crash due to this.
Anyone could explain this? Thanks!

see this code and its log:
NSString *string1 = [NSString stringWithString:#"a"];
NSString *string2= #"a";
NSLog(#"String1: %p", string1);
NSLog(#"String2: %p", string2);
2012-03-22 13:21:49.433 TableDemo[37385:f803] String1: 0x5860
2012-03-22 13:21:49.434 TableDemo[37385:f803] String2: 0x5860
as you see [NSString stringWithString:#"a"]; doesn't create a new string, it uses the string literal #"a". And string literals can't be deallocated.
Try your code with NSMutableString and you will see a crash.

I am not an expert about this, so please take this with a grain of salt. I guess that [NSString stringWithString:#"a"] will probably just return the literal string #"a", i.e. it just returns its argument. As #"a" is a literal, it probably resides in constant memory and can't be deallocated (so it should be initialized with a very high retain count).

[NSString stringWithString:#"a"] returns an autoreleased object. That means "the true" retain count is 2 not 1 in line 4. In line 6 you are overreleasing your variable but the crash will happen later - on the autorelease pool drain.

Related

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!
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.

Need assistance regarding NSString

In NSString NSString Class Reference what this means
Distributed objects:
Over distributed-object connections, mutable string objects are passed by-reference and immutable string objects are passed by-copy.
And NSString can't be changed, so what happening when I am changing str in this code
NSString *str = #"";
for (int i=0; i<1000; i++) {
str = [str stringByAppendingFormat:#"%d", i];
}
will I get memory leak? Or what?
What your code is doing:
NSString *str = #""; // pointer str points at memory address 123 for example
for (int i=0; i<1000; i++) {
// now you don't change the value to which the pointer str points
// instead you create a new string located at address, lets say, 900 and let the pointer str know to point at address 900 instead of 123
str = [str stringByAppendingFormat:#"%d", i]; // this method creates a new string and returns a pointer to the new string!
// you can't do this because str is immutable
// [str appendString:#"mmmm"];
}
Mutable means you can change the NSString. For example with appendString.
pass by copy means that you get a copy of NSString and you can do whatever you want; it does not change the original NSString
- (void)magic:(NSString *)string
{
string = #"LOL";
NSLog(#"%#", string);
}
// somewhere in your code
NSString *s = #"Hello";
NSLog(#"%#", s); // prints hello
[self magic:s]; // prints LOL
NSLog(#"%#", s); // prints hello not lol
But imagine you get a mutable NSString.
- (void)magic2:(NSMutableString *)string
{
[string appendString:#".COM"];
}
// somewhere in your code
NSString *s = #"Hello";
NSMutableString *m = [s mutableCopy];
NSLog(#"%#", m); // prints hello
[self magic2:m];
NSLog(#"%#", m); // prints hello.COM
Because you pass a reference you can actually change the "value" of your string object since you are working with the original version and not a duplicate.
NOTE
String literals live as long as your app lives. In your exmaple it means that your NSString *str = #""; never gets deallocated. So in the end after you have looped through your for loop there are two string objects living in your memory. Its #"" which you cannot access anymore since you have no pointer to it but it is still there! And your new string str=123456....1000; But this is not a memory leak.
more information
No, you will not get memory leak with your code, as you are not retaining those objects in the loop, they're created with convenience method, you don't own them, and they will be released on next cycle of autorelease pool. And, it's doesn't matter if you are using ARC or not, objects created with convenience methods and not retained are released wherever they are out of their context.
In will not leak memory, but will get more memory allocation, due to making new copy of immutable copy as many time loop triggers [str stringByAppendingFormat:#"%d", i];.
Memory leak will get performed when, you put your data unreferenced, or orphan, this will not make your last copy of string orphan every time when loops, but will clear all copies of NSString when operation get complete, or viewDidUnload.
You will not get a memory leak in the example code because Automatic Reference Counting will detect the assignment to str and (automatically) release the old str.
But it would be much better coding style (and almost certainly better performance) to do this:
NSMutableString* mstr = [NSMutableString new];
for(int i = 0; i < 1000; ++i){
[mstr appendFormat:#"%d",i];
}
NSString* str = mstr;
...
As to the first question, I think it means that a change made to a mutable string by a remote process will be reflected in the originating process's object.

Objective C, what [NSString initWithFormat] exactly does?

I just would like to know the difference between the line 1 and 2 bellow:
_subtitle = #"Test"; //Line 1
_subtitle = [NSString stringWithFormat: #"Test"]; //Line 2
If I asked that question, it is because I got a problem by using MKAnnotation. In the method bellow, I try to update the subtitle delegate property of MKAnnotation (which is nonatomic, copy and readonly). But it's look like that I got a zombie when using the line 2 and nothing when using the line 1. So my question is why?
- (void) initCoordinateWithAddress:(NSString*)address;
{
self.address = address;
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString: address completionHandler:^(NSArray *placemarks,NSError *error)
{
CLPlacemark *place = [placemarks objectAtIndex:0];
_coordinate = place.location.coordinate;
_title = self.address;
_subtitle = #"Test"; //Line 1: don't crash
_subtitle = [NSString stringWithFormat: #"Test"]; //Line 2: crash
//_subtitle = [[NSString stringWithFormat: #"[%.2f,%.2f]", self.coordinate.latitude, self.coordinate.longitude] copy];
_isInit = YES;
[self.customDelegate didCalculateCoordinate: place.location.coordinate forAnnotation: self];
}];
}
I actually already fixed my problem by using the method copy, but I still not understand what is the difference between the line 1 and 2, if anyone can help me to understand what the difference is, I will appreciate.
Edit:
1- I am not using ARC
2- _subtitle comes form #synthesize subtitle = _subtitle; And subtitle is a part of the MKAnnotation protocol, with the property nonatomic, readonly and copy
Regards,
Cyril
If you are not using ARC, the answer is straightforward and is what Anoop Vaida wrote. However, I think some further explanation is needed.
This line
_subtitle = #"Test";
Creates a reference to a string literal. If you take a peak at its retain count in the current implementation of foundation, you'll find it is a very large number (NSIntegerMax I think). If the code for -release and -retain comes across this value for the retain count, they do not decrement or increment it. Thus string literals have infinite life times.
This line:
_subtitle = [NSString stringWithFormat: #"Test"];
creates a string you do not own. Unless you take steps to claim ownership, it could disappear at any time, most likely when the autorelease pool is drained. Your options are create a string you do own
_subtitle = [[NSString alloc] initWithFormat: #"Test"];
or to retain it.
_subtitle = [NSString stringWithFormat: #"Test"];
[_subtitle retain]; // Can be combined with the previous line if you like.
or to copy it
_subtitle = [[NSString stringWithFormat: #"Test"] copy];
Note that, in all cases, you need to release the previous value of _subtitle before you overwrite it, or you will get a leak e.g.
[_subtitle release];
_subtitle = [[NSString alloc] initWithFormat: #"Test"];
This is why it is better to have a property. Just because the MKAnnotation subtitle property is read only, does not mean you can't override it with your own read/write property. e.g.
#interface MyAnnotation : NSObject <MKAnnotation>
// other stuff
#property (readwrite, copy, nonatomic) NSString* subtitle;
#end
If you then synthesize it, you'll get all the correct memory management code and you can just do
[self setSubtitle: [NSString stringWithFormat: #"test"]];
or, if you must use dot notation
self.subtitle = [NSString stringWithFormat: #"test"];
I just would like to know the difference between the line 1 and 2
bellow:
_subtitle = #"Test"; //Line 1
_subtitle = [NSString stringWithFormat: #"Test"]; //Line 2
If you ask just the above these both are same.
While checking your code, the difference is quite visible.
You are creating a new autoreleased subtitle which is getting released once the block is over.
I don't think your solution is to understand how the string initializes work, but more on how blocks deal with variables.
When I think about it I think you may want to try an access _subtitle by it's property and not it's ivar.
self.subtitle
This should increment the retain count and keep everything functioning fine.
If you look up the documentation for initWithFormat: it links you to Formatting String Objects with many examples.
This basically allows (s)printf-style format strings, like so:
NSString *string1 = [[NSString alloc] initWithFormat:#"A string: %#, a float: %1.2f",
#"string", 31415.9265];
// string1 is "A string: string, a float: 31415.93"
The key is to specify arguments by adding a , after the string argument.
The '[NSString stringWithFormat:]' allows you to add a variable into the string, for example:
int myVar = 3;
NSString *myString = [NSString stringWithFormat:#"This number is %i", myVar];
The resulting string would be (if you were to NSLog it, for example): "This number is 3"
However you cannot do it like this:
NSString *myString = #"This number is %i", myVar;
Which would present you with an error.

Objective-C: Weak attritube don't work as expected [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why do weak NSString properties not get released in iOS?
I'm a newbie to Objective C and I've got some questions that I cannot answer myself.
I have a block of code for testing __weak variable (I'm using ARC, of course):
NSString *myString = [[NSString alloc] initWithFormat:#"John"];
NSString * __weak weakString = myString;
myString = nil; //<-- release the NSString object
NSLog(#"string: %#", weakString);
The output of the above codes is as expected, since weakString is a weak variable :
2013-01-02 11:42:27.481 ConsoleApp[836:303] string: (null)
But when I modified the code to this:
NSString *myString = [[NSString alloc] initWithFormat:#"John"];
NSString * __weak weakString = myString;
NSLog(#"Before: %#", weakString); //<--- output to see if the __weak variable really works.
myString = nil;
NSLog(#"After: %#", weakString);
The output is totally not what I expected:
2013-01-02 11:46:03.790 ConsoleApp[863:303] Before: John
2013-01-02 11:46:03.792 ConsoleApp[863:303] After: John
The output of the latter NSLog must have been (nil) instead of "John". I've tried to search in many documents but I haven't found the answer for this case.
Can someone give an reasonable explaination? Thanks in advance.
The NSLog function is retaining the passed NSString in an autorelease pool. The zeroing-weak variable will therefore not be zeroed until the autorelease pool has drained. For example:
__weak NSString* weakString = nil;
#autoreleasepool {
NSString* myString = [[NSString alloc] initWithFormat:#"Foo"]; // Retain count 1
weakString = myString; // Retain count 1
NSLog(#"A: %#", weakString); // Retain count 2
NSLog(#"B: %#", weakString); // Retain count 3
myString = nil; // Retain count 2
NSLog(#"C: %#", weakString); // Retain count 3
NSAssert(weakString != nil, #"weakString is kept alive by the autorelease pool");
}
// retain count 0
NSAssert(weakString == nil, #"Autorelease pool has drained.");
Why is NSLog putting the string into an autorelease pool? That's an implementation detail.
You can use the debugger or Instruments to follow the retain count of the NSString instance. The exact retain counts are unimportant, but it does shed some light as to what's going on behind the scenes. What is important is that the NSString instance is deallocated when the autorelease pool is drained.
I think it’s just some implementation detail. Your weak variable is getting cleared, but not just immediately. For example, this works as expected:
NSString *myString = [[NSString alloc] initWithFormat:#"John"];
NSString * __weak weakString = myString;
#autoreleasepool {
NSLog(#"Before: %#", weakString);
myString = nil;
}
NSLog(#"After: %#", weakString); // nil

ios: Retain count of 2147483647? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
NSString retainCount is 2147483647
Objective C NSString* property retain count oddity
Have a look at the following code:
NSString* testString = [[NSString alloc] initWithString:#"Test"];
NSLog(#"[testString retainCount] = %d", [testString retainCount] );
NSMutableArray* ma = [[NSMutableArray alloc] init];
[ma insertObject:testString atIndex:0];
[testString release];
NSLog(#"%#", [ma objectAtIndex:0]);
This is the output on the console :
[testString retainCount] = 2147483647
Test
How can this happen? I expected 1 not 2147483647!
You initiate your NSString object with string literal and 2 following things happen:
As NSString is immutable -initWithString: method optimizes string creation so that your testString actually points to a same string you create it with (#"Test")
#"Test" is a string literal and it is created in compile time and lives in a specific address space - you cannot dealloc it, release and retain does not affect its retain count and it is always INT_MAX
With all mentioned above you still should work with your string object following memory management rules (as you created it with alloc/init you should release it) and you'll be fine
You can only have two expectations for the result of retainCount:
1) It's greater than 1. You cannot predict what number it will actually be because you don't know who else is using it. You don't know how somebody else is using it. It's not a number you should care about.
2) People will tell you not to use it. Because you shouldn't. Use the rules to balance your retains and releases. Do not use retainCount. It will frustrate and confuse you, for no value.

Resources