文档章节

iOS arc下循环引用问题

求是科技
 求是科技
发布于 2015/06/05 16:12
字数 688
阅读 23
收藏 0

原文出处:http://blog.cnbang.net/tech/2085/

自己理解

开发时,用老框架ASIHttpRequest请求时(现在使用AFNetWorking),有时候会出现发不出请求的情况,项目开启了ARC,代码如下:

@implement MainController
- (void) fetchUrl{
    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:currUrl]];
    [request setCompletionBlock:^{
        NSLog(@"completed");
    }];
    [request startAsynchronous];
}
@end

排查后发现,request这个对象在执行完setCompletionBlock方法后,被释放掉了,也就不会执行[request startAsynchronous]这里,自然也发不出请求。

解决办法:

由于使用了ARC,也没法手动调用[request remain]让这个变量不被释放,所以只能将这个变量改成实例变量,让Controller存在时一直持有该对象不被释放。

修改成如下:

@interface MainController {
     ASIHTTPRequest *request;
}
@end
 
@implement MainController
- (void) fetchUrl{
    request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:currUrl]];
    [request setCompletionBlock:^{
        [self complete];
    }];
    [request setFailedBlock:^{
          NSLog(@"failed");
    }];
    [request startAsynchronous];
}
@end

这样又有新的问题了

XCode编译后提示[self complete]这一行可能会导致循环引用

重点理解“循环引用”处来了

因为MainController实例对象持有属性request,而request持有方法setCompletionBlock,但是setCompletionBlock方法里面又持有MainController实例对象,这样就导致循环引用,MainController实例对象在外面引用计数为0时仍然无法释放,因为request里面持有MainController实例对象的引用,其引用计数永远大于1。

导致循环引用的原因在于setCompletionBlock里面调用的self是一个strong类的引用,会使self引用计数+1。解决方法就是声明一个__weak变量指向self,这样block使用这个变量时就不会导致self引用计数+1,不会导致循环引用。

@implement MainController
- (void) fetchUrl{
     request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:currUrl]];
     __weak id this = self;
 
    [request setCompletionBlock:^{
        [this complete];
    }];
    [request startAsynchronous];
}
@end

新的问题,在block中如果只是调用MainController的方法,上面就能完美解决问题,但是现在需要在block中调用很多实例变量,包括赋值等,如下

@interface MainController {
     ASIHTTPRequest *request;
     BOOL isLoading;
     UIView *loadingView;
}
@end
 
@implement MainController
- (void) fetchUrl{
    request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:currUrl]];
 
    [request setCompletionBlock:^{
        isLoading = NO;
        loadingView.hidden = NO;
    }];
    [request startAsynchronous];
}
@end

xcode提示说isLoading = NO和loadingView.hidden = NO两行可能循环引用,解决方法如下:

实例变量全部加上get set方法,通过弱引用对象访问即可,缺点是破坏了封装性,把原本私有的实例变量变成公有的。

@interface MainController {
     ASIHTTPRequest *request;
}
@property (nonatomic, strong) UIView *loadingView;
@property (nonatomic, assign) BOOL isLoading;
@end
 
@implement MainController
@synthesize loadingView, isLoading;
 
- (void) fetchUrl{
     request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:currUrl]];
     __weak id this = self;
 
    [request setCompletionBlock:^{
        this.isLoading = NO;
        this.loadingView.hidden = NO;
    }];
    [request startAsynchronous];
}
@end


新框架(AFNetworking)如下方法解决上述问题

__weak __typeof(&*self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
__strong __typeof(&*weakSelf)strongSelf = weakSelf;
if (!strongSelf) {
return;
}
strongSelf.networkReachabilityStatus = status;
if (strongSelf.networkReachabilityStatusBlock) {
strongSelf.networkReachabilityStatusBlock(status);
}
};




© 著作权归作者所有

求是科技

求是科技

粉丝 98
博文 451
码字总数 232301
作品 0
成都
后端工程师
私信 提问
iOS 编写高质量Objective-C代码(五)

级别: ★★☆☆☆ 标签:「iOS」「内存管理」「Objective-C」 作者: MrLiuQ 审校: QiShare团队 前言: 这几篇文章是小编在钻研《Effective Objective-C 2.0》的知识产出,其中包含作者和小...

QiShare
2018/09/05
0
0
理解 iOS 和 macOS 的内存管理

在 iOS 和 macOS 应用的开发中,无论是使用 Objective-C 还是使用 swift 都是通过引用计数策略来进行内存管理的,但是在日常开发中80%(这里,我瞎说的,8020 原则嘛)以上的情况,我们不需要...

Mr_zebra
2018/11/20
0
0
2018 iOS 面试题大全(补充完整版)

原文地址:2018 iOS 面试题大全 由于原作者并没有继续更新,这里我转过来继续更新下 这个栏目将持续更新--请iOS的小伙伴关注! 1、iOS 应用导航模式有哪些? 2、iOS 中持久化方式有哪些? 3、...

Theendisthebegi
2018/11/15
0
0
iOS开发之ARC(自动引用计数)

自动引用计数(ARC)是在MacOS X 10.7与iOS 5中引入一项新技术,用于管理Objective-C中的对象。它废弃了显式的retain、release和autorelease消息,而且在两个平台的表现一致。 由于有限的内存...

JoeyBlue
2013/02/23
14.7K
15
IOS 浅谈闭包block的使用

前言:对于ios初学者,block通常用于逆向传值,遍历等,会使用,但是可能心虚,会感觉block很神秘,那么下面就一起来揭开它的面纱吧。 ps: 下面重点讲叙了闭包的概念,常用的语法,以及访问变...

周雨奇
2018/07/23
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Visual Paradigm 教程[UML]:如何绘制封装图?(上)

下载Visual Paradigm最新试用版 查看本教程视频文件 在项目开始时,您只有有限数量的图表,一切都简单而美观。然而,当时间过得匆匆时,已经创建了越来越多的图表,并且它们开始变得无法管理...

xiaochuachua
47分钟前
2
0
Pure-ftpd服务安装及虚拟用户设置

安装 sudo apt-get install pure-ftpd 虚拟用户设置 首先,可以在系统中添加相应的用户和组,如用户ftpuser 和组ftpgroup ,专门用来管理ftp服务。也可以是能登录系统的用户,但最好是不能登...

Gm_ning
48分钟前
1
0
一位面试了阿里,滴滴,网易,蚂蚁金服,最终有幸去了网易的Java程序员【面试题分享】

前言 15年毕业到现在也近三年了,最近面试了阿里集团(菜鸟网络,蚂蚁金服),网易,滴滴,点我达,最终收到点我达,网易offer,蚂蚁金服二面挂掉,菜鸟网络一个月了还在流程中... 最终有幸去...

Java领航员
50分钟前
3
0
“大团队”和“敏捷开发”,谁说不可兼得?

阿里妹导读:当小团队的产出跟不上业务需要,团队就面临规模化的问题。从1个团队到3个团队,仍可以通过简单的团队沟通保持高效协作。当产品复杂到需要5个以上团队同时开发时,我们需要一定的...

阿里云云栖社区
54分钟前
1
0
基于虹软人脸识别Demo android人脸识别

参加一个比赛,指定用虹软的人脸识别功能,奈何虹软人脸识别要自己建人脸库,不然就只能离线用,总不能装个样子,简单看了下虹软Demo,下面决定用这种简单方法实现在线人脸识别: Android端(...

是哇兴哥棒棒哒
59分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部