【问题标题】:How to fix the memory leaks in Objective-C?如何修复 Objective-C 中的内存泄漏?
【发布时间】:2015-09-21 09:49:57
【问题描述】:

我构建了一个从 HockeyApp 获取报告的简单应用程序。但是,当我使用内存泄漏工具运行应用程序时,它显示当我执行 getReport 操作时存在内存泄漏。我无法理解仪器中显示的所有信息。

这是导致内存泄漏的按钮操作方法:

- (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{

}

我发现内存泄漏发生在didRecieveData 方法中出现警报视图之前。

这里是内存泄漏工具显示内存泄漏的截图:

我不明白代码的哪一部分导致了内存泄漏。谁能告诉我如何使用泄漏工具识别导致内存泄漏的代码部分?

编辑:当我在模拟器上运行应用程序时,仪器没有显示任何内存泄漏:

截图如下:

当我在设备上运行应用程序时,仪器再次显示内存泄漏:

我查看了泄漏部分,发现 NSmutableArray 导致了泄漏:

我在我的代码中只使用了一个NSMutableArray。我在.h 文件中声明了它:

@property (nonatomic,strong) NSMutableArray *reportArray;

并分配到viewDidLoad:

reportArray=[[NSMutableArray alloc]init];

并将其加载到didRecieveData:

 [reportArray addObject:obj[@"reason"]];

堆栈跟踪快照:

【问题讨论】:

  • 请注意,其中一个 Instruments 按钮,就在右侧的“快照”上方,选择了一个堆栈跟踪,可以显示泄漏对象的分配是如何发生的。
  • 添加了堆栈跟踪快照!!!

标签: ios objective-c memory-leaks instruments


【解决方案1】:

试试这个:

reportArray = [[[NSMutableArray alloc] init] autorelease];

在您的 connectionDidFinishLoading:connection:didFailWithError: 方法集中

reportArray = nil

最后在 Project > Build Phases > Compile Sources 添加-fno-objc-arc 作为编译器标志此文件 (已编辑,抱歉)。然后再次点击Product菜单>Analyze (command + shift + B),查看内存泄漏是否依然存在。

【讨论】:

  • P.S.同样在connection:didReceiveResponse:方法中分配和初始化reportArray
  • 我正在使用 ARC。我想我不能提到自动释放。
  • 我明白了。如果您将 -fno-objc-arc 标志添加到 Build Phases > Compile Sources 文件列表中的特定文件,则该文件的 ARC 将被禁用。
  • 分析后没有发现任何泄漏。泄漏仅显示在仪器上
  • 仍然,“自动发布”的想法对您有用吗?它适用于我的所有应用程序。
【解决方案2】:

这可能是 Apple 的泄漏——确实看起来它来自 UIAlertView / UIAlertConnection。您可以尝试使用 UIAlertConnection 实现警报,看看它是否会消失——Apple 可能没有对向后兼容的 UIAlertView 实现进行太多测试。

它不会出现在泄漏中,但请注意 NSURLConnection 保留其委托,并且在您的情况下,您的委托保留它看起来像的 NSURLConnection。如果我没记错的话,那应该是一个保留循环。当连接完成或失败时,请务必断开它(取消委托,或取消控制器上的连接)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-07
    • 1970-01-01
    相关资源
    最近更新 更多