簡體   English   中英

在ARC下,IBOutlets應該強還是弱?

[英]Should IBOutlets be strong or weak under ARC?

我正在使用ARC專為iOS 5開發。 IBOutletUIView (和子類)應該strong還是weak

下列:

@property (nonatomic, weak) IBOutlet UIButton *button;

將擺脫所有這些:

- (void)viewDidUnload
{
    // ...
    self.button = nil;
    // ...
}

這樣做有什么問題嗎? 從“接口生成器”編輯器直接連接到標題時,模板使用的功能很strong就像自動生成的屬性一樣,但是為什么? UIViewController已經對其view進行了strong引用,並保留了其子視圖。

警告,過時的答案 :根據WWDC 2015,此答案不是最新的,有關正確答案,請參閱上面的公認答案 (丹尼爾·霍爾)。 該答案將留作記錄。


來自開發人員庫的摘要:

從實際的角度來看,在iOS和OS X中,出口應定義為已聲明的屬性。 出口通常應該較弱,但從文件所有者到筆尖文件(或iOS中的情節提要場景)中頂級對象的出口則應較堅固。 因此,默認情況下,您創建的插座通常較弱,因為:

  • 您為視圖控制器的子視圖或窗口控制器的窗口的子視圖創建的出口是對象之間的任意引用,並不表示所有權。

  • 強勢出口經常由框架類指定(例如,UIViewController的視圖出口或NSWindowController的窗口出口)。

     @property (weak) IBOutlet MyView *viewContainerSubview; @property (strong) IBOutlet MyOtherClass *topLevelObject; 

蘋果公司目前建議的最佳做法是使IBOutlets 強,除非特別需要弱化以避免保留周期。 正如Johannes所述,在WWDC 2015的“在Interface Builder中實現UI設計”會議中對此進行了評論,其中蘋果工程師說:

我要指出的最后一個選項是存儲類型,可以是強類型或弱類型。 通常,您應該使出口堅固,尤其是當您將出口連接到子視圖或不總是由視圖層次結構保留的約束時。 真正需要弱化出口的唯一情況是,如果您有一個自定義視圖,該視圖引用了備份視圖層次結構的內容,通常不建議這樣做。

我在Twitter上向IB團隊的一名工程師詢問了此問題,他確認將默認設置為“ 強” ,並且正在更新開發人員文檔。

https://twitter.com/_danielhall/status/620716996326350848 https://twitter.com/_danielhall/status/620717252216623104

盡管文檔建議對子視圖使用weak屬性,但是從iOS 6開始,最好使用strong (默認所有權限定符)。 這是由於UIViewController中的更改導致不再卸載視圖而引起的。

  • 在iOS 6之前,如果您保持指向控制器視圖子視圖的強鏈接,則如果視圖控制器的主視圖被卸載,只要視圖控制器在周圍,這些視圖就會保留在子視圖中。
  • 從iOS 6開始,視圖不再被卸載,而是被加載一次,然后只要它們的控制器在那里就一直存在。 因此,強大的屬性無關緊要。 它們也不會創建強參考周期,因為它們指向強參考圖。

也就是說,我在使用之間感到恐懼

@property (nonatomic, weak) IBOutlet UIButton *button;

@property (nonatomic) IBOutlet UIButton *button;

在iOS 6及更高版本中:

  • 明確使用weak表示控制器不希望擁有按鈕。

  • 但是,在不卸載視圖的情況下,忽略weak不會對iOS 6造成傷害,並且更短。 有人可能會指出這也更快,但是由於IBOutlet weak ,我還沒有遇到一個太慢的應用程序。

  • 不使用weak可被視為錯誤。

底線:從iOS 6開始,只要我們不使用視圖卸載,就不會再犯此錯誤。 參加聚會的時間。 ;)

我認為沒有任何問題。 在ARC之前,我一直將IBOutlets assign ,因為它們已被其超級視圖保留。 如果您使它們變weak ,則不必像您指出的那樣在viewDidUnload中將它們刪除。

一個警告:您可以在ARC項目中支持iOS 4.x,但如果這樣做,您就不能使用weak ,因此您必須將它們assign ,在這種情況下,您仍然想在其中引用無效。 viewDidUnload避免指針懸空。 這是我遇到的懸空指針錯誤的示例:

UIViewController具有用於郵政編碼的UITextField。 它使用CLLocationManager反向對用戶的位置進行地理編碼並設置郵政編碼。 這是委托回調:

-(void)locationManager:(CLLocationManager *)manager
   didUpdateToLocation:(CLLocation *)newLocation
          fromLocation:(CLLocation *)oldLocation {
    Class geocoderClass = NSClassFromString(@"CLGeocoder");
    if (geocoderClass && IsEmpty(self.zip.text)) {
        id geocoder = [[geocoderClass alloc] init];
        [geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
            if (self.zip && IsEmpty(self.zip.text)) {
                self.zip.text = [[placemarks objectAtIndex:0] postalCode];
            }
        }];    
    }
    [self.locationManager stopUpdatingLocation];
}

我發現,如果我在適當的時間解雇了該視圖,並且沒有在viewDidUnload中將self.zip設置為nil,則委托回調可能會在self.zip.text上引發錯誤的訪問異常。

出於性能原因, IBOutlet應該堅固。 請參閱情節提要參考,Strong IBOutlet,iOS 9中的場景擴展塢

如本段所述,視圖控制器視圖的子視圖的出口可能很弱,因為這些子視圖已經由nib文件的頂級對象擁有。 但是,當將插座定義為弱指針並設置了指針時,ARC會調用運行時函數:

id objc_storeWeak(id *object, id value);

這將使用對象值作為鍵將指針(對象)添加到表中。 該表稱為弱表。 ARC使用此表存儲應用程序的所有弱指針。 現在,當對象值被釋放時,ARC將遍歷弱表並將弱引用設置為nil。 或者,ARC可以致電:

void objc_destroyWeak(id * object)

然后,該對象被取消注冊,並且objc_destroyWeak再次調用:

objc_storeWeak(id *object, nil)

與發布弱參考相關的簿記工作可能比發布強參考相關的時間長2–3倍。 因此,弱引用會導致運行時的開銷,您只需將出口定義為強即可避免這種開銷。

從Xcode 7開始,它表明功能strong

如果您觀看WWDC 2015會議407 在Interface Builder中實現UI設計 ,則建議使用(抄本來自http://asciiwwdc.com/2015/sessions/407

我要指出的最后一個選項是存儲類型,可以是強類型或弱類型。

通常,您應該使出口堅固,尤其是當您將出口連接到子視圖或視圖層次結構中並不總是會保留的約束時。

真正需要弱化出口的唯一情況是,如果您有一個自定義視圖,該視圖引用了備份視圖層次結構的內容,通常不建議這樣做。

因此,我將選擇“ strong”,然后單擊“ connect”,這將生成我的插座。

在iOS開發中,NIB加載與Mac開發略有不同。

在Mac開發中,IBOutlet通常是一個較弱的參考:如果您有NSViewController的子類,則僅保留頂層視圖,並且在取消分配控制器時,將自動釋放其所有子視圖和出口。

UiViewController使用鍵值編碼使用強引用來設置出口。 因此,當您取消分配UIViewController時,頂視圖將自動取消分配,但您還必須在dealloc方法中取消分配其所有出口。

在Big Nerd Ranch的這篇文章中 ,他們涵蓋了這個主題,並解釋了為什么在IBOutlet中使用強引用不是一個好選擇(即使Apple在這種情況下建議這樣做)。

我想在這里指出一件事,那就是,盡管蘋果工程師在其自己的WWDC 2015視頻中說過:

https://developer.apple.com/videos/play/wwdc2015/407/

蘋果一直在改變主意,這告訴我們這個問題沒有唯一正確的答案。 為了表明即使是Apple工程師在這個問題上也存在分歧,請看一下Apple最新的示例代碼,您會看到有些人使用弱功能,而有些人則不使用。

這個Apple Pay示例使用了以下弱點: https : //developer.apple.com/library/ios/samplecode/Emporium/Listings/Emporium_ProductTableViewController_swift.html#//apple_ref/doc/uid/TP40016175-Emporium_ProductTableViewController_swift-DontLinkElementID_8

就像該畫中畫示例一樣: https : //developer.apple.com/library/ios/samplecode/AVFoundationPiPPlayer/Listings/AVFoundationPiPPlayer_PlayerViewController_swift.html#//apple_ref/doc/uid/TP40016166-AVFoundationPiPPlayer_PlayerViewController_swift-DontLinkElementID_4

和Lister示例一樣: https : //developer.apple.com/library/ios/samplecode/Lister/Listings/Lister_ListCell_swift.html#//apple_ref/doc/uid/TP40014701-Lister_ListCell_swift-DontLinkElementID_57

核心位置示例也是如此: https : //developer.apple.com/library/ios/samplecode/PotLoc/Listings/Potloc_PotlocViewController_swift.html#//apple_ref/doc/uid/TP40016176-Potloc_PotlocViewController_swift-DontLinkElementID_6

和視圖控制器預覽示例一樣: https : //developer.apple.com/library/ios/samplecode/ViewControllerPreviews/Listings/Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_swift.html#//apple_ref/doc/uid/TP40016546-Projects_PreviewUsingDelegate_Pre_Controller

就像HomeKit的例子一樣: https : //developer.apple.com/library/ios/samplecode/HomeKitCatalog/Listings/HMCatalog_Homes_Action_Sets_ActionSetViewController_swift.html#//apple_ref/doc/uid/TP40015048-HMCatalog_Homes_Action_Sets_ActionSetViewController_swift-Do

所有這些都針對iOS 9進行了全面更新,並且都使用弱電插座。 由此我們可以了解到A.問題並不像某些人說得那么簡單。 B.蘋果反復改變主意,C。您可以使用任何讓自己開心的東西:)

特別感謝Paul Hudson(www.hackingwithsift.com的作者)給了我澄清,並提供了此答案的參考。

我希望這可以更好地闡明這個主題!

照顧自己。

從WWDC 2015開始,有一個關於在Interface Builder中實現UI設計的會議。 他說,在32 @IBOutlet左右,您總是想使@IBOutlet 更強

請注意, IBOutletCollection應該為@property (strong, nonatomic)

看起來這些年來已經發生了一些變化,現在蘋果建議一般使用強壯的。 他們的WWDC會話的證據在會話407-在Interface Builder中實現UI設計 ,開始於32:30。 他說的話我的筆記是(幾乎,如果不完全是引用他的話):

  • 通常,出口連接應該牢固,特別是如果我們連接的子視圖或約束並不總是由視圖層次結構保留的話

  • 創建自定義視圖時,可能需要弱的插座連接,該自定義視圖引用了視圖層次結構中備份的內容,通常不建議這樣做

在其他方面,只要我們的某些自定義視圖沒有在視圖層次結構中使某些視圖向上創建保留周期,它現在應該一直很強大

編輯:

有些人可能會問這個問題。 用強引用保留它並不會創建保留周期,因為根視圖控制器和擁有視圖會保留對它的引用? 還是為什么發生了這種變化? 我認為答案是在本演講的早期,當時他們描述了筆尖是如何通過xib創建的。 為VC和視圖創建了一個單獨的筆尖。 我認為這可能是他們更改建議的原因。 從蘋果那里得到更深層次的解釋仍然是很好的。

我認為最重要的信息是:xib中的元素自動出現在視圖的子視圖中。 子視圖是NSArray。 NSArray擁有它的元素。 等對他們有很強的指導意義。 因此,在大多數情況下,您不想創建另一個強指針(IBOutlet)

借助ARC,您無需在viewDidUnload執行任何操作

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM