Как да коригирате изтичането на памет в 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

и накрая в Проект > Фази на изграждане > Изходни източници за компилиране добавете -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