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==>%@\nErrorCode==>%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操作,这些地方往往也是内存泄漏产生的地方。