1,AFNetWorking 内存泄漏
原理:
https://www.jianshu.com/p/4584ace111b2
解决方法:
网上很多文章都说AFNetWorking有内存泄漏问题,其实是使用者自己的问题,他们的解决方法是将AFHTTPSessionManager写成单例,用该单例进行网络请求。
其实不然。AFHTTPSessionManager继承于AFURLSessionManager,AFURLSessionManager有个属性session,session类型是NSURLSession,调用NSURLSession进行请求后,等请求完毕后调用session的finishTasksAndInvalidate方法,或者调用取消session的invalidateAndCancel方法,再或者将session属性置成nil,这样AFURLSessionManager就能正常释放,这样就不需要将AFHTTPSessionManager写成单例来使用了。NSURLSession将代理属性delegate强引用了,所以NSURLSession影响了其delegate的释放,调用其中的一个invalidate方法时,就会将其delegate引用计数减一,这样其delegate就能正常释放了,这里的delegate就是AFURLSessionManager。
service.task = [self.sessionManager POST:service.urlString parameters:service.dataDictionary progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { if (service.isShowLoadingView) [MBProgressHUD hideHUD]; //网络请求成功(包含过滤服务器定义的错误码操作,实现在子类) [self responseHandler:responseObject service:service]; } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { //网络请求错误处理操作 [service requestFail:ERROR_CODE_FAILURE errorMessage:REQUEST_FAILURE]; if (service.isShowLoadingView) [MBProgressHUD hideHUD]; //错误提示 NSInteger statusCode = ((NSHTTPURLResponse *)task.response).statusCode; if (statusCode == 0) { statusCode = error.code; } [self requestFailWithService:service statusCode:statusCode]; // NSLog(@"URL==>%@ ErrorCode==>%d===ErrorMessage==>%@",service.urlString,ERROR_CODE_FAILURE,REQUEST_FAILURE); }]; [self.sessionManager.session finishTasksAndInvalidate]; //释放
2,
GSKeyChain
将 原代码:
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service { return [NSMutableDictionary dictionaryWithObjectsAndKeys: (__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass, service, (__bridge_transfer id)kSecAttrService, service, (__bridge_transfer id)kSecAttrAccount, (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,(__bridge_transfer id)kSecAttrAccessible, nil]; }
换成:
static NSMutableDictionary * queryDIC; + (NSMutableDictionary *)getKeychainQuery:(NSString *)service { if (!queryDIC) { queryDIC =[NSMutableDictionary dictionaryWithObjectsAndKeys: (__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass, service, (__bridge_transfer id)kSecAttrService, service, (__bridge_transfer id)kSecAttrAccount, (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,(__bridge_transfer id)kSecAttrAccessible, nil]; } return queryDIC; }
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service KeychainHelper内存泄露
https://www.jianshu.com/p/4c1618c97410
3,
///获取ssid + (NSString *)getWifiName { NSArray* ifs = (__bridge_transfer id)CNCopySupportedInterfaces(); id info = nil; for (NSString *ifnam in ifs){ info = (__bridge id)CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam); if (info && [info count]) break; } NSString *wifiname = info[@"SSID"]; return UNNULL_STRING(wifiname); }
id bridge 换成 CFBridgingRelease
如:
///获取ssid + (NSString *)getWifiName { NSArray *ifs = CFBridgingRelease(CNCopySupportedInterfaces()); id info = nil; for (NSString *ifnam in ifs){ info = CFBridgingRelease(CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam)); if (info && [info count]) break; } NSString *wifiname = info[@"SSID"]; return UNNULL_STRING(wifiname); }
4
- (void)setModels { //获取当前类 id infoClass = [self class]; unsigned int count = 0; Ivar *members = class_copyIvarList([infoClass class], &count); //获取属性列表 for (int i = 0 ; i < count; i++) { //遍历属性列表 Ivar var = members[i]; const char *memberType = ivar_getTypeEncoding(var); //获取变量类型 NSString *typeStr = [NSString stringWithCString:memberType encoding:NSUTF8StringEncoding]; //判断类型是否为字典——只处理物的模型中的属性 if ([typeStr isEqualToString:@"@"NSDictionary""]) { const char *memberName = ivar_getName(var); //获取变量名称 [self setModelWithDicName:[NSString stringWithCString:memberName encoding:NSUTF8StringEncoding] channel:IOTBaseModelValueChangedChannel_Get]; } } free(members); //添加 }
Ivar *members = class_copyIvarList([infoClass class], &count); //获取属性列表 这句报了leak,加 free(members); 来释放掉。
原理:Runtime方法中的class_copyIvarList,class_copyMethodList这些方法返回的对象没有被手动释放导致的内存泄漏。因为这些是C实现的函数,是需要手动对函数返回值进行free的,不然则会导致内存泄露。= =。这里也顺便提醒平时需要注意对于C/C++的实现,当见到malloc/new分配的对象,就应该检查该对象有没有对应的free/delete操作,这些地方往往也是内存泄漏产生的地方。