I am currently doing the CS193P lessons via iTunesU and the teacher mentioned the Build and Analyze option several times. He said that it was a nice tool and fun to play with.
So I tried, and noticed that it doesn't work, or that I don't understand how it should work (I think the last option).
I have a few memory leaks, and it is not warning me at all! I saw online that a blue thing should appear telling me it is a leak, but I don't see anything although I'm doing NSDictionary *dict = [[NSDictionary alloc] init];.
How is it supposed to work? From what I read on the internet I thought it should signal potential leaks. What am I doing wrong?
I'm using XCode 3.2.5.
Thanks.
Update:
This is a kind of bug, I think.
When I declare this in the interface like NSDictionary *dict; and initialize it (but nowhere deallocating it) it says nothing.
When I declare and initialize it in - (void) init and don't release it in there like:
- (void) init {
if(self = [super init])
NSDictionary *dict = [[NSDictionary alloc] init];
return self;
}
It does signal a leak. Why? Is this because of my settings? Is this a bug? If it is a bug, where and how should I report it?
It's giving you a warning because you're not deallocating it.
-(void)dealloc{
[super dealloc];
[dict dealloc];
}
It's not warning you because you should be able to release the objects as soon as you create them, and the analyzer goal is to alert you on possible leaks in your code.
You can either use autorelease, or you dealloc the object you create manually.
P.S., little curiosity: why are you using Xcode 3.2.5?
Don't know exactly if that version can, but in the latest versions of Xcode, when you run that tool, you are able to see WHAT object you are deallocating with the means of some arrows with explanation, something like
I just found out that a reboot and restart of Xcode will bring it back.
Related
I find that my app holds a lot of memory when the web view has already been released.Because my app needs to load many webpages.This is my release function called in the dealloc method.
[[NSURLCache sharedURLCache] removeAllCachedResponses];
[[_webView mainFrame] loadHTMLString:#"" baseURL:nil];
[_webView stopLoading:nil];
[_webView removeFromSuperview];
[_webView setResourceLoadDelegate:nil];
[_webView setFrameLoadDelegate:nil];
[_webView release];
_webView = nil;
But there is nothing happen when do this.It's still a lot of memory being holder.What should I do?
Things to try:
Run Build and Analyze and fix every error it generates.
Use Instrument's Leaks tool to find memory leaks
Audit your code to make sure you aren't keeping a retained reference somewhere.
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!
It does leak. Put a breakpoint on dealloc (or create a subclass of NSAlert and add a log statement to dealloc) to show this
The accessry view should be released. You alloc it and then it would be retained by the alertView
Here's a concise guide on when to use retainCount.
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:
Use ARC.
If you cannot follow rule one (for instance, you are developing for OS X 10.5 as I do), then here are the rules:
You must balance each call you make to +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.
I have an application in Xcode 4.6 that connects with Facebook. I have noticed that every so often when the application goes into the background and returns to the foreground, there are occasional crashes at varying points in the application. Being inconsistent, the crashes were difficult to analyze, so I tried using instruments to identify memory leaks. I am quite new to iOS, and although I was able to successfully determine that I do have memory leaks, and I can even see which methods are triggering them, I find myself thinking, "well what now?" In other words, I see where the problem is, but yet I can't identify it. I am hoping if I highlight an example, someone can shed some light.
**Here is what I am looking at in instruments:
Just looking at the first leaked object in the list:
Leaked Object = "FB Session"
Responsible Frame =
+[FBSession openActiveSessionWithPermissions:allowLoginUI:allowSystemAccount:isRead:defaultAudience:completionHandler:]
I interpret this to mean that there is some leaked object existing inside of this method. Is that correct? The implemented method exists in my App Delegate and looks like:
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI {
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"user_about_me",
#"read_friendlists",
nil];
//IMPLEMENTED METHOD
return [FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
[self sessionStateChanged:session
state:state
error:error];
}];
}
At this point, I am not sure what I need to do, or what about this method could even be causing a leak. I have looked though memory leak tutorials, but they only got me to the point of locating the problem, but stop short of helping me figure out how to solve it. Any help is appreciated.
Generally you shouldn't pass self to block as block retains it. It seems, that FBSession also retains completionHandler, so it becomes a retain cycle.
In order to break it, use one of the following constructions:
__weak FBSession *zelf = self; // OK for iOS 5 only
__unsafe_unretained FBSession *zelf = self; // OK for iOS 4.x and up
__block FBSession *zelf = self; // OK if you aren't using ARC
and then
return [FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
[**zelf** sessionStateChanged:session
state:state
error:error];
}];
See this post for more complete explanation of what retain cycles are.
I am using latest Xcode, and trying to find memory leaks.
When i use 'Analyze'
It shows following as potential leak:
+ (UITableViewCell *) method {
UITableViewCell *cell = [[TestX alloc]init];
... do some stuff
return [cell autorelease];
}
Should i just ignore it ?
No, you shouldn't ignore warnings. Sometimes Xcode is buggy and forgets you've changed the code. Try restarting Xcode. Remove do some stuff so that it's just the two lines and see if the analyser stops warning you. It could be the case that you're affecting the retain count in that code somewhere without realising it.
You need to name the method properly to show that it's returning an autoreleased object. I forget the preferred name. Try something like 'newObject'.
I've got a MFMailComposeViewController object that I'm releasing in my Email button's callback, simply because I created it, and I think my doing so is intermittently but not always crashing my app.
How can I use Xcode's instrumentation program to detect such a situation?
Thanks.
You can set the NSZombieEnabled environment variable to YES (Product > Edit Scheme…, the select Run (Product Name), click the Arguments tab and edit the list of environment variables). With NSZombie, objects will not be deallocated but turned into zombies. Messaging them will log an error to the console instead of crashing with EXC_BAD_ACCESS. That way you can find out if it’s really the MFMailComposeViewController that’s causing trouble.
But retaining and releasing the view controller might not even be necessary. If you present the MFMailComposeViewController immediately after creating it and don’t use it anymore after it’s been dismissed, there’s no need to retain it:
- (IBAction)composeMessage:(id)sender {
MFMailComposeViewController *mailComposeViewController = [[[MFMailComposeViewController alloc] init] autorelease];
mailComposeViewController.mailComposeDelegate = self;
[self presentModalViewController:mailComposeViewController animated:YES];
}
- (void)mailComposeController:(MFMailComposeViewController *)mailComposeViewController didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
// Present error to the user if failed
[self dismissModalViewControllerAnimated:YES];
}