iOS经验总结

关于项目中两个内存泄露问题的解决

2018-06-27  本文已影响113人  mark666

最近跳槽一家新公司,接手了以前的一个4年的老项目,传言中间有4个以上的人接手过,这中间代码质量也是没有任何把控的,所以为了提升系统健壮性,在完成项目新需求的同时进行着性能的优化,最近可能更多的记录一些优化方面的东西,这篇文章展示两个内存的泄露的例子:

1.NSDate

     NSDate *date = [[NSDate alloc] init];
     date = [date initWithTimeIntervalSince1970:42];

     NSDate *date = [NSDate date];
     date = [date initWithTimeIntervalSince1970:42];

很多人在创建date 不注意这一点,上述两种方式创建方式都会造成内存泄露,我们通过instruments 定位到泄露情况:

而 产生错误的原因很简单,新生成一个 date 对象,用date 指向生成的这个对象,此时这个对象的引用计数为1, 然后[date initWithTimeIntervalSince1970:42] 这个也会生成一个新的对象,date 指向这个对象,这个对象引用计数也为1,当出了作用域,date销毁了,第二次产生对象也随之销毁,而第一次产生的对象是无法销毁的,引用计数始终为1.

所以我们通常正确的创建的方式是生成并持有一个对象,避免产生多个无法访问的对象

NSDate *date = [[NSDate alloc] initWithTimeIntervalSince1970:42]

这样就不会产生内存泄露。

2.AFNetworking 使用问题

很多人在使用 AFNetworking 时候可能没有关注过这个问题,错误的使用AFNetworking 进行网络请求而导致内存泄露。

- (void)GET:(NSString *)url
        parameters:(NSDictionary *)param
        success:(void (^)(id _Nullable requestData))success
        failure:(void (^)(NSError  * _Nullable  error))failure{

    AFHTTPSessionManager *operationManage = [AFHTTPSessionManager manager];
    operationManage.requestSerializer = [AFJSONRequestSerializer serializer];
    operationManage.responseSerializer = [AFJSONResponseSerializer serializer];

    [operationManage GET:url parameters:param progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
    }];

有的人不注意这个细节,每次请求都会重新创建一个 AFHTTPSessionManager , 这样就会导致内存泄露,具体的大家可以通过工具查看一下泄露的产生,我查看了一下网上,大家的通常说封装成一个单例就好了,很多人可能不太了解这个原因,以及为什么要这样做,我大概解释一下,大家就明白了这个原因

首先AFHTTPSessionManager 我们通过 manager获取其实例的, 并且 是继承于 AFURLSessionManager, 而 AFURLSessionManager 中一个会话对象NSURLSession *session,而这个对象创建时候有一个代理属性是 retain,当你重新再发一次网络请求时候,上一次NSURLSession *sessiondelegate 产生循环引用无法被释放了,除非你主动调用一下 '[mgr.session invalidateAndCancel]',这样才可以释放掉。

这样你就很容易理解内存泄露问题的根源了,解决起来就容易了

解决方案一

通过网上大众做法封装成一个单例,获取封装成一个static 变量在网络封装类initialize中初始化, 当然这种方式你得确保你URL和参数设置的请求头是一致的,如果不一致,这样做肯定是不可以的。

解决方案二

每次请求结束主动调用一次取消

[operationManage.session invalidateAndCancel];

这样就能够解决了这种内存泄露。

上一篇下一篇

猜你喜欢

热点阅读