There's a point of memory management I'm not 100% clear on, suppose there is the following code:
{
NSString *string = [[NSString alloc] init];
string = [[NSString alloc] init];
}
Does this cause a memory leak of the first allocation? If not why not?
Under ARC, this does not leak memory. This is because any time a strong object pointer is changed, the compiler automatically sends a release to the old object. Local variables, like NSString *string, are strong by default.
So your code above gets compiled to something more like this:
{
NSString *string = [[NSString alloc] init];
// Oh, we're changing what `string` points to. Gotta release the old value.
[string release];
string = [[NSString alloc] init];
}
Conceptually, BJ is correct, but the generated code is slightly different. It goes something like this:
NSString *string = [[NSString alloc] init];
// Oh, we're changing what `string` points to. Gotta release the old value.
NSString *tmpString = string;
string = [[NSString alloc] init];
[tmpString release];
[string release]; // string goes out of scope at this point in your code
This order of operation is usually not that critical (and if you care too much about it, you are probably coding incorrectly). But understanding it explains why the objects are destroyed exactly when they are.
No it does not cause a leak. ARC will release the first string before it sets the second string. This is the truly amazing power of ARC!
Related
Are all objects in the iOS automatically added to the autorelease pool?When ARC? If no, which one will be added & which one not?
eg:
{
NSString *str = [[NSString alloc] init];
NSString *str2 = [NSString string];
}
+ (NSString *)string {
return [[NSString alloc] init];
}
str2 will be added to autorelease pool because it creates by a method that name as 'copy/mutableCopy/alloc/new'. So it does not create by self. But I don't know is str will be added or not and why?
ARC makes no guarantees as to what objects are added to the autorelease pool and what objects are not. It is very possible that neither of the objects in your example are ever added to the autorelease pool under ARC.
The answer is NO. In fact, which will be added auto release pool is obj of method "string".
// ARC
{
NSString __strong *str = [[NSString alloc] init]; // STEP A
NSString __strong *str2 = [NSString string]; // STEP B
}// STEP Finish
+ (NSString *)string {
id obj = [[NSString alloc] init];
return obj;
}
Like this may help you understand.In ARC, object has __strong modifier(default).Because a object must has a strong pointer point to it, or it die.
STEP A : str create a NSString object and strong point to itself.
STEP B : str2 not create but strong point to a object which is obj.obj created by NSString in method string, because it needs return, so added to auto release pool. And str2 strong point to obj, so obj can't release by auto release pool, there still a strong pointer point to it.
STEP Finish,str,str2 out of method, no more strong pointer .So they had release.
At STEP B, why will needs auto release pool? Because if don't put obj into auto release pool, it will release by compiler, just like str in the STEP Finish.
All this from the book "Pro multithreading and memory management for iOS and OS X".
Forget my poor English.
NSString *str1 = [[NSString alloc]init];
NSString *str2 = [[NSString alloc]init];
NSLog(#"%p\n%p",str1,str2);
result
str1:0x7fff7b559d00
str2:0x7fff7b559d00
Why str1 and str2 have same memory address?
NSString is immutable, so two empty strings are identical. Therefore, Cocoa can return the same object every time you create it.
The real question, however, how can this be done when alloc returns two different addresses for the two strings?
The answer is that init is allowed to substitute the value of self for anything it wishes, and return a completely different object. For example, NSString's init can be implemented like this:
-(id)init {
static NSString *empty = nil;
if (!empty) {
empty = [[NSString alloc] initWithCharacters:"" length:0];
}
return empty;
}
Note: The real code in Cocoa will almost certainly be different; this is only an illustration to show how the same address could be returned for different allocations.
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.
I've created autorelease pool. localString has added to this pool. I released the pool. localString and string must be deallocated. But in reality they are still alive. You can see my log:
Why is the string object still alive? I don't know.
and code:
-(NSString*) happyString
{
NSString *localString = [[[NSString alloc] initWithString:#"I don't know."] autorelease];
return localString;
}
-(IBAction) onButton:(id)sender
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *string = [self happyString];
[pool release];
NSLog(#"Why is the string object still alive? %#", string);
}
Strings (NSString instances and statically allocated strings with #"") are immutable in Cocoa, so when you try to create a new NSString from a statically allocated one, the NSString class can make an optimisation: a new NSString instance is not created (the object created when you called -alloc is immediately released), and the reference to your statically allocated string is returned. That is, the line:
NSString *localString = [[[NSString alloc] initWithString:#"I don't know."] autorelease];
Is actually equivalent to:
NSString *localString = #"I don't know.";
(If you check the memory addresses of those two objects, you can see that they are the same.)
As this type of string cannot be released, it does not disappear when you expect it to.
If you were to create your string in a way that cannot be optimised, for example:
NSString *localString = [[[NSString alloc] initWithFormat:#"%#", #"I don't know."] autorelease];
Then your code will behave as you expect, and your application will (hopefully) crash at your NSLog line.
If you have tried any classes (any custom classes) other than NSString , then it would not be alive..
I have NSMutableArray* cityData that I fill with custom LocationDetail objects. cityData is created in viewDidLoad and released in dealloc.
Somewhere in the code, based on user actions, I populate LocationDetail and add it to cityData array:
LocationDetail* d = [[LocationDetail alloc] init];
d.city = [NSString stringWithFormat:#"%S", (char*)sqlite3_column_text16(statement, 1)];
d.tz = [NSString stringWithFormat:#"%S", (char*)sqlite3_column_text16(statement, 3)];
d.country = [NSString stringWithFormat:#"%S", (char*)sqlite3_column_text16(statement, 2)];
d._id = [NSString stringWithFormat:#"%S", (char*)sqlite3_column_text16(statement, 0)];
[cityData addObject:d];
[d release];
When I am finished with the view controller and remove it, Leaks utility says I have a leak in the code above in NSCFString in all 4 lines with [NSString stringWithFormat] above.
I tried removing the sqlite3 stuff and simplified the call to something like
d._id = [NSString stringWithFormat:#"%s", "a string"]
with the same result. However, if I replace the NSString stringWithFormat like this:
d._id = #"a string";
the leak goes away. I wonder why there is a leak if I use the stringWithFormat, but not if I use #"something". Is there anything obvious that I'm doing wrong?
Thanks!
Properties are not automatically released for you, you need to do that yourself in
- (void)dealloc
See The Objective-C Programming Language: Declared Properties for an example.
Edit:
It seems that the example was moved into the Advanced Memory Management Programming Guide.