全部的引用計數系統,都存在循環應用的問題。spa
例以下面的引用關係對象:代理
a建立並引用到了對象b.指針
對象b建立並引用到了對象c.orm
對象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銷燬,不會形成強引用。it
代理爲何要用weak以下圖:io
假設把代理設置成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];
}