所有的引用计数系统,都存在循环应用的问题。
例如下面的引用关系对象:
a创建并引用到了对象b.
对象b创建并引用到了对象c.
对象c创建并引用到了对象b.
这时候b和c的引用计数分别是2和1。当a不再使用b,调用release释放对b的所有权,因为c还引用了b,所以b的引用计数为1,b不会被释放。b不释放,c的引用计数就是1,c也不会被释放。从此,b和c永远留在内存中,造成内存浪费。这种情况,必须打断循环引用,通过其他规则来维护引用关系。
那么普通控件为什么要用weak:
如下图控制器中的View通过[self.view addSubview:btn];已经将Btn增加了强引用,所以不会被销毁,所以如果想把btn当做属性,没有必要在property中使用强引用浪费资源。
如果要用强引用也可以,因为在控制器销毁之后,控制器view也销毁了,所以btn销毁,不会造成强引用。
代理为什么要用weak如下图:
假设把代理设置成strong那么就会执行语句UIScrollView*scrollView=[UIScrollView alloc]init];scrollView.delegate=self;(self代表控制器)后,
当控制器想要销毁时,控制器被一个强指针指着,而scrollView添加到控制器view中也被强指针指着,也无法销毁,那么它的delegate不会销毁。delegate指向控制器。造成了循环引用。把delegate变成weak:当控制器生命周期结束时,view随之销毁,内部子空间也随之销毁,delegate也就销毁了。
block内用到了外面的东西,需要转换成weak指针,否则会造成循环引用 如下图:
有这样一段代码,代码本意不必理解:mail有一个block属性,那么block内有个邮件控制器需要设置代理。
ShareViewController内部强指针指向用Group,Group内部的items强指针指向mail对象,mail对象有个option属性(block),option内部用到了self也就是控制器,所以block(option是copy类型的)会用一个强指针指向self。注意:这里不和上边一样,不要被vc的代理(代理是weak的)所迷惑,是block强指针指向了self。造成了循环引用谁都没办法被销毁。
解决办法:使用:
__unsafe_unretained typeof(self) selfVc =self;
或
__unsafe_unretained HYShareViewController *selfVc =self;在block中让他对self只能进行弱引用。
或者把__unsafe_unretain改成__weak。(__unsafe_unretain和__weak的区别请见下一篇<OC语法--__unsafe_unretain、__strong、__weak、__autoreleasing这四种属性的作用>)
HYSettingItem *mail = [HYSettingArrowItemitemWithIcon:@"MailShare"title:@"邮件分享"destVcClass:nil];
mail.option = ^{
//不能发邮件
if (![MFMailComposeViewControllercanSendMail])return;
MFMailComposeViewController *vc = [[MFMailComposeViewControlleralloc]init];
[vcsetSubject:@"会议"];
[vc setMessageBody:@"今天下午开会吧"isHTML:NO];
vc.mailComposeDelegate = selfVc;
//显示控制器
[selfVc presentViewController:vcanimated:YEScompletion:nil];
};
HYSettingGroup *group = [[HYSettingGroupalloc]init];
group.items =@[sina, sms, mail];
[self.dataaddObject:group];
}