无法联络AFNetworking内存泄露

问题描述:

TL; DR:克隆和检查泄漏自己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/

泄漏出现在此处:

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?当我在AFHTTPSessionManager上同时触发两个连接时会发生什么? – Kuba

+0

@Kuba我已经更新了答案,请检查。 – degapps

+0

谢谢,'[manager invalidateSessionCancelingTasks:YES];'works – Kuba