2016-12-27 2 views
0

TL; DR: Clone и проверить утечку себя https://github.com/JakubMazur/SO41343532/оставляющей след памяти AFNetworking утечки

У меня есть один класс, который обрабатывать всю мою сеть. Это называется ResponseOrganizer и там у меня есть метод класса:

+ (void)getSth:(void (^)(NSURLSessionDataTask *operation, NSArray *locales, id plainObject))success failure:(void (^)(NSURLSessionDataTask *operation, NSError *error))failure { 

    Connection *connection = [Connection new]; 
    connection.urlString = @"http://sample-file.bazadanni.com/download/txt/json/sample.json"; 
    connection.requestMethodType = GET; 

    [connection fireWithSuccess:^(NSURLSessionDataTask *operation, NSArray *returnArray, id originalResponse) { 
     success(operation, returnArray, originalResponse); 
    } failure:^(NSURLSessionDataTask *operation, NSError *error) { 
     failure(operation, error); 
    }]; 
} 

Где Connection это единственный мой внутренний объект соединения:

Вот реализация:

#import "Connection.h" 

@interface Connection() 
@property (weak,nonatomic) AFHTTPSessionManager *manager; 
@end 

@implementation Connection 

#pragma mark - Connection groundwork 

-(void)fireWithSuccess:(void (^)(NSURLSessionDataTask *operation, NSArray* returnArray, id originalResponse))success failure:(void (^)(NSURLSessionDataTask *operation, NSError *error))failure { 

    self.manager = [AFHTTPSessionManager manager]; 
    [self.manager urlString:self.urlString withMethod:self.requestMethodType parameters:self.paramaters success:^(NSURLSessionDataTask *operation, id responseObject) { 
     success(operation,@[responseObject],nil); 
    } failure:^(NSURLSessionDataTask *operation, NSError *error) { 
     failure(operation,error); 
    }]; 
} 

@end 

И у меня есть категория называющийся правильный способ внутри AFNetworking. Для того, чтобы упростить его выглядеть следующим образом:

-(void)urlString:(NSString*)urlString withMethod:(RequestMethodType)method parameters:(NSDictionary*)parameters success:(void (^)(NSURLSessionDataTask *operation, id responseObject))success failure:(void (^)(NSURLSessionDataTask *operation, NSError *error))failure { 
    switch (method) { 
     case GET: { 
      [self getWithURLString:urlString parameters:parameters success:^(NSURLSessionDataTask *operation, id responseObject) { 
       success(operation,responseObject); 
      } failure:^(NSURLSessionDataTask *operation, NSError *error) { 
       failure(operation,error); 
      }]; 
      break; 
     } 
} 

И когда я хочу, чтобы сделать запрос, например, в моем ViewController Я делаю это так:

[ResponseOrginizer getSth:^(NSURLSessionDataTask *operation, NSArray *locales, id plainObject) { 

} failure:^(NSURLSessionDataTask *operation, NSError *error) { 

}]; 

И когда я запускаю его в приборостроении я всегда получение:

enter image description here

И здесь не имеет значения, он приземлится на блоке успеха/неудачи, он всегда вызывает утечку. Я извлекаю все из этого и ставил его на github как можно проще. Github ссылка: https://github.com/JakubMazur/SO41343532/

ответ

4

появляется здесь Утечка:

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; 

кажется, что причина в том же (или аналогичный), как описано here - NSURLSession ПРОВЕЛ сохранил ссылку на делегат.

Изменить Вам код в Connection.m как это, чтобы избежать утечек:

-(void)fireWithSuccess:(void (^)(NSURLSessionDataTask *operation, NSArray* returnArray, id originalResponse))success failure:(void (^)(NSURLSessionDataTask *operation, NSError *error))failure { 
    AFHTTPSessionManager *manager = [Connection manager]; 

    [manager urlString:self.urlString withMethod:self.requestMethodType parameters:self.paramaters success:^(NSURLSessionDataTask *operation, id responseObject) { 
     success(operation,@[responseObject],nil); 
    } failure:^(NSURLSessionDataTask *operation, NSError *error) { 
     failure(operation,error); 
    }]; 
} 

+ (AFHTTPSessionManager*) manager 
{ 
    static dispatch_once_t onceToken; 
    static AFHTTPSessionManager *manager = nil; 
    dispatch_once(&onceToken, ^{ 
     manager = [AFHTTPSessionManager manager]; 
    }); 

    return manager; 
} 

Если вам нужно обрабатывать несколько сеансов, вы можете использовать другой подход: позвонить -[AFHTTPSessionManager invalidateSessionCancelingTasks:], когда вы закончите с сессией, например:

-(void)fireWithSuccess:(void (^)(NSURLSessionDataTask *operation, NSArray* returnArray, id originalResponse))success failure:(void (^)(NSURLSessionDataTask *operation, NSError *error))failure { 
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; 

    [manager urlString:self.urlString withMethod:self.requestMethodType parameters:self.paramaters success:^(NSURLSessionDataTask *operation, id responseObject) { 
     success(operation,@[responseObject],nil); 
     [manager invalidateSessionCancelingTasks:YES]; 
    } failure:^(NSURLSessionDataTask *operation, NSError *error) { 
     failure(operation,error); 
     [manager invalidateSessionCancelingTasks:YES]; 
    }]; 
} 

(Примечание: пройти YES, если вы хотите, чтобы отменить отложенные задания, NO в противном случае).

+0

Почему Singleton? что произойдет, когда я запускаю два соединения одновременно в моем AFHTTPSManManager? – Kuba

+0

@ Куба Я обновил ответ, пожалуйста, проверьте. – degapps

+0

Спасибо, '[менеджер invalidateSessionCancelingTasks: YES];' работает – Kuba

Смежные вопросы