内存泄漏解一波
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。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ///获取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
如:
1 2 3 4 5 6 7 8 9 10 11 12 13 | ///获取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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | - ( 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); //添加 } |
1 | Ivar *members = class_copyIvarList([infoClass class ], &count); //获取属性列表 这句报了leak,加 free(members); 来释放掉。 |
原理:Runtime方法中的class_copyIvarList,class_copyMethodList这些方法返回的对象没有被手动释放导致的内存泄漏。因为这些是C实现的函数,是需要手动对函数返回值进行free的,不然则会导致内存泄露。= =。这里也顺便提醒平时需要注意对于C/C++的实现,当见到malloc/new分配的对象,就应该检查该对象有没有对应的free/delete操作,这些地方往往也是内存泄漏产生的地方。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
2015-01-19 IOS学习基础