Как исправить утечки памяти в Objective-C?

Я создал простое приложение, которое получает отчеты из 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"]];

Снимки Stacktrace:

введите описание изображения здесь введите описание изображения здесь  введите описание изображения здесь


person Teja Nandamuri    schedule 03.07.2015    source источник
comment
Обратите внимание, что одна из кнопок инструментов, чуть выше снимков справа, выбирает трассировку стека, которая может показать, как происходит выделение просочившегося объекта.   -  person Phillip Mills    schedule 03.07.2015
comment
Добавлены снимки трассировки стека !!!   -  person Teja Nandamuri    schedule 03.07.2015


Ответы (2)


Попробуй это:

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

в ваших connectionDidFinishLoading: и connection:didFailWithError: методах, установленных

reportArray = nil

и, наконец, в Project> Build Phases> Compile Sources добавьте -fno-objc-arc в качестве флага компилятора для этого файла (отредактировано, извините). Затем снова щелкните меню «Продукт»> «Анализировать» (command + shift + B) и проверьте, все ли происходит утечка памяти.

person Lucifer    schedule 03.07.2015
comment
P.S. также выделить и инициализировать reportArray в методе connection:didReceiveResponse:. - person Lucifer; 03.07.2015
comment
Я использую ARC. Я думаю, что не могу упомянуть автоспуск. - person Teja Nandamuri; 03.07.2015
comment
Я вижу это. Если вы добавите флаг -fno-objc-arc к определенному файлу в списке файлов Фазы сборки ›Источники компиляции, ARC будет отключен для этого файла. - person Lucifer; 03.07.2015
comment
После анализа я не заметил никаких утечек. Утечки были показаны только на приборах. - person Teja Nandamuri; 03.07.2015
comment
Тем не менее, подходит ли вам идея «автозапуска»? У меня он отлично работает во всех моих приложениях. - person Lucifer; 03.07.2015
comment
Я попробую. Я боюсь, что если я отключу ARC, мне нужно будет позаботиться обо всем, и в некоторых местах я могу получить больше этих утечек. - person Teja Nandamuri; 03.07.2015
comment
С помощью этого флага, добавленного на этапах сборки, вы отключаете ARC только для этого конкретного файла, а не для всех файлов. - person Lucifer; 03.07.2015
comment
Извините, мне пришлось изменить пути к моим файлам :) Политика компании .... Итак, вот мой XCode с проектом, над которым я сейчас работаю: i.imgur.com/q9A6VkM.jpg - person Lucifer; 03.07.2015
comment
Я проанализировал его и обнаружил утечку в этой строке: NSData * jsonData = [responseString dataUsingEncoding: NSUTF8StringEncoding]; - person Teja Nandamuri; 03.07.2015
comment
Позвольте нам продолжить это обсуждение в чате. - person Lucifer; 03.07.2015
comment
Почему вы выделяете NSString из аргумента NSData, а затем NSData из этого NSString. Почему бы вам не использовать параметр напрямую (например, `NSDictionary * JSON = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: & e];` Таким образом NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; и NSData *jsonData = [responseString dataUsingEncoding:NSUTF8StringEncoding]; не нужны. - person Lucifer; 04.07.2015

Возможно, это утечка Apple - похоже, она исходит от UIAlertView / UIAlertConnection. Вы можете попробовать реализовать предупреждение с помощью UIAlertConnection и посмотреть, исчезнет ли оно - Apple, возможно, не так много тестировала обратно совместимую реализацию UIAlertView.

Это не будет отображаться в утечках, но имейте в виду, что NSURLConnection сохраняет своего делегата, и в вашем случае у вас есть делегат, сохраняющий NSURLConnection, как это выглядит. Если я не ошибаюсь, это должен быть цикл сохранения. Не забудьте разорвать его (обнулить делегата или обнулить соединение на вашем контроллере), когда соединение завершается или терпит неудачу.

person Carl Lindberg    schedule 04.07.2015