Currently I didn't use ARC in my app, and I tried to create a NSAlert object as a local variable, at the end of function, I didn't release it. I expected that the app crash with that, the function code is here.
#define GLOBAL_VARIABLE 0
NSString *msgText = [self.defaultValueTextFiled stringValue];
NSString *informativeText = @"Informative Text";
#if !GLOBAL_VARIABLE
NSAlert *alertView = nil;
#endif
if (alertView == nil)
{
alertView = [[NSAlert alloc] init];
[alertView setMessageText:msgText];
[alertView setInformativeText:informativeText];
NSTextField *accessory = [[NSTextField alloc] initWithFrame:NSMakeRect(0,0,200,22)];
[accessory setStringValue:@"accessory result"];
[alertView setAccessoryView:accessory];
}
NSView *accessory= nil;
NSInteger result = [alertView runModal];
if (result == NSAlertAlternateReturn)
{
accessory = [alertView accessoryView];
if (accessory != nil)
{
NSTextField *txtFiled = (NSTextField *)accessory;
NSLog(@"%ld", [accessory retainCount]);
NSString *str = [txtFiled stringValue];
NSLog(@"%ld", [accessory retainCount]);
[self.resultValueTextField setStringValue:str];
NSLog(@"%ld", [accessory retainCount]);
}
}
Questions: (1) There is no [alertView release] in the end, why not crash? It has even no leaks.
(2) Refer to here , the accessory view shouldn't be release. However, I tried to release the view before [alertView runModal], then get its stringValue later, that could works. Why?
(3) The return value of function retainCount is interesting. When I created the alertView object, the retainedCount of alertView is 3. (Why?)
Before [alertView setAccessoryView:accessory], the accessory's retainedCount is 1, then it changed to 2 after executing it. That's normal and right. However, the log result for the above code, they're 20, 21, 22. How did they come from?
Thanks for your attention!
The rules for memory management are generally quite simple. Most problems come from overthinking them and trying to guess what other parts of the system are going to do, rather than just following the rules as written.
The first rule of Memory Management:
If you cannot follow rule one (for instance, you are developing for OS X 10.5 as I do), then here are the rules:
+alloc…
, +new…
, -…copy…
or -retain
with a call to -release
or -autorelease
.That's really it. Everything else is really just commentary to help you follow that rule. So, you called [NSAlert alloc]
and [NSTextField alloc]
, you need to call release
on those objects.
Why doesn't it crash?
Because a leak is not going to crash unless it causes you to run out of memory.
Why doesn't it leak?
The most likely cause is that you're only running it once and then expecting Instruments to detect the leak. It may not show up if you only run it once. It depends on how NSAlert
is internally implemented. Instruments finds leaks by walking all the pointers in the system and determining if any accessible pointers still reference a piece of allocated memory. There are many cases when a "leak is not a leak."
But this also suggests you're not running the static analyzer, because the analyzer should definitely have detected that leak. Run the static analyzer (Cmd-Shift-B) all the time and clean up what it finds.
the accessory view shouldn't be release.
That's not what the link you reference says. You shouldn't add an extra release
. But in the referenced code, you'll notice that they release the view to balance their own +alloc
.
… retainCount …
Never use -retainCount
. Not even for debugging. Not even for anything else. There is no point at which retainCount
is going to return you a piece of information that is going to be more enlightening than confusing. Why is it greater than you think it should be? Because other objects are retaining the alert view? Which objects? That's not your business. That's an internal implementation detail, subject to change. It could be pending autorelease
calls, which show up temporarily as a "too high retainCount
". It could be the run loop. It could be an internal controller. It could be anything. Calling retainCount
tells you nothing useful.
Now that you understand manual memory management, switch to ARC and think about object graphs rather than retain counts. It is a much better way to deal with memory.