内存泄漏解一波

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

 
原文地址:https://www.cnblogs.com/developer-qin/p/10292261.html