I built a simple app which gets the reports from HockeyApp. However when I run the app with the memory leak instruments, it showed there was a memory leak when I perform the getReport action. I couldn't understand all the information shown in the instrument.
Here is the button action method which causes the memory leak:
- (IBAction)getReports:(id)sender {
//initialize url that is going to be fetched.
NSURL *url = [NSURL URLWithString:@"https://rink.hockeyapp.net/api/2/apps/APP_ID/crash_reasons"];
//initialize a request from url
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request addValue:tokenReceived forHTTPHeaderField:@"X-HockeyAppToken"];
[request setHTTPMethod:@"GET"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
//initialize a connection from request
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
self.getReportConnection = connection;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)data{
if (connection==getReportConnection) {
[self.receivedData appendData:data];
NSLog(@"data is %@",data);
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSError *e = nil;
NSData *jsonData = [responseString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:jsonData options: NSJSONReadingMutableContainers error: &e];
NSLog(@"login json is %@",JSON);
NSLog(@"reason json is %@",JSON[@"reason"]);
[JSON[@"crash_reasons"] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[reportArray addObject:obj[@"reason"]];
NSLog(@"index = %lu, Object For title Key = %@", (unsigned long)idx, obj[@"reason"]);
}];
NSError *error = nil;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:jsonData
options:kNilOptions error:&error];
if (error != nil) {
NSLog(@"Error parsing JSON.");
}
else {
NSLog(@"Array: %@,array count is %d", jsonArray,jsonArray.count);
}
// [reportArray addObject:[jsonArray objectAtIndex:0]];
if (JSON!=NULL) {
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"Reports succesfully retrieved" message:@"" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles: nil];
[alert show];
}
}
}
// This method receives the error report in case of connection is not made to server.
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
UIAlertView *errorAlert=[[UIAlertView alloc]initWithTitle:@"Wrong Login" message:nil delegate:self cancelButtonTitle:@"ok" otherButtonTitles: nil];
[errorAlert show];
NSLog(@"error is %@",error);
}
// This method is used to process the data after connection has made successfully.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
}
I see that the memory leak occurs just before the alert view appears in the didRecieveData
method.
Here is the screenshot of the memory leak instrument showing memory leak:
I couldn't understand which part of the code causes the memory leak. Can anyone tell me how to identify the part of code that causes the memory leak with the leak instrument?
Edit: When I run the app on the simulator, the instrument didnt show any memory leak:
Here is the screenshot:
Again When I run the app on device, the instrument showed me the memory leak:
I looked into the leaks section and I found NSmutableArray
is causing the leak:
I used only one NSMutableArray
in my code. I declared it in .h
file:
@property (nonatomic,strong) NSMutableArray *reportArray;
and allocated it in viewDidLoad
:
reportArray=[[NSMutableArray alloc]init];
and loaded it in didRecieveData
:
[reportArray addObject:obj[@"reason"]];
Stacktrace snapshots:
Try this:
reportArray = [[[NSMutableArray alloc] init] autorelease];
in your connectionDidFinishLoading:
and connection:didFailWithError:
methods set
reportArray = nil
and finally in Project > Build Phases > Compile Sources add -fno-objc-arc
as compiler flag for this file (edited, sorry) . Then click Product menu >Analyze (command + shift + B) again and check if the memory leak still occurs.
It is possible it is Apple's leak -- sure looks like it is coming from UIAlertView / UIAlertConnection. You might try implementing the alert using UIAlertConnection and see if it goes away -- Apple may not have tested the back-compatible UIAlertView implementation as much.
It won't show up in leaks, but be aware that NSURLConnection retains its delegate, and in your case you have your delegate retaining the NSURLConnection it looks like. That should be a retain loop if I'm not mistaken. Be sure to break it (nil out the delegate, or nil out the connection on your controller) when the connection finishes or fails.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.