IBOutlet'ler ARC altında güçlü mü yoksa zayıf mı olmalı?


551

ARC kullanarak yalnızca iOS 5 için geliştiriyorum. Meli IBOutletiçin s UIViews (ve alt sınıfları) olmak strongveya weak?

Aşağıdaki:

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

Tüm bunlardan kurtulacaktım:

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

Bunu yaparken herhangi bir sorun var mı? Şablonlar strong, 'Arayüz Oluşturucu' düzenleyicisinden doğrudan başlığa bağlanırken oluşturulan otomatik olarak oluşturulan özellikler gibi kullanıyorlar , ama neden? UIViewControllerZaten var strongonun referansı viewolan subviews korur hangi.


11
Not olarak IBOutletCollection()olmamalı weak, aksi halde olarak döner nil.
ohho

Xcode 8.2.1, arayüz oluşturucu aracılığıyla IBOutlet'ler oluştururken zayıf kullanır. Ancak burada SO üzerinde birçok cevap güçlü kullanmanızı önerir.
neoneye

1
@neoneye Sadece xcode 8.3.2 ile storyboard'dan hızlı dosyaya sürükleme denedim ve varsayılan olarakstrong
CupawnTae

Yanıtlar:


252

Apple tarafından önerilen mevcut en iyi uygulama, IBOutlet'lerin bir tutma döngüsünü önlemek için özellikle zayıf olmadıkça güçlü olması içindir . Johannes'un yukarıda belirttiği gibi, bu, bir Apple Mühendisinin söylediği WWDC 2015'in "Arayüz Oluşturucu'da UI Tasarımlarını Uygulama" oturumunda yorumlandı:

Ve belirtmek istediğim son seçenek, güçlü veya zayıf olabilen depolama türüdür. Genel olarak, özellikle bir alt görünüme veya her zaman görünüm hiyerarşisi tarafından korunmayacak bir kısıtlamaya bir çıkış bağlıyorsanız, çıkışınızı güçlendirmelisiniz. Bir çıkışı gerçekten zayıflatmanız için gereken tek zaman, görünüm hiyerarşisini yedekleyen bir şeye başvuran ve genel olarak önerilmeyen özel bir görünümünüz varsa.

Bunu Twitter'da IB ekibindeki bir mühendise sordum ve güçlü olanın varsayılan olması gerektiğini ve geliştirici belgelerinin güncellenmekte olduğunu doğruladı .

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


33
Bu gerçekten doğru mu veya 300+ upvotes ile cevap doğru mu? Film şeridinden
.h'ye

4
400+ oyu olan oysa doğru ama modası geçmiş. İOS 6 viewDidUnload çağrılmadığından, zayıf prizlere sahip olmanın hiçbir faydası yoktur.
16'da kjam

7
@kjam faydaları vardır. Her şeyden önce, yaratmadığınız bir şeye güçlü bir referans vermemelisiniz. İkincisi, performans artışı göz ardı edilebilir. Programlamadaki en iyi uygulamaları ihlal etmeyin, çünkü bir adam, iyi yerleştirilmiş bir adam bile, bunun 10 mikrosaniye daha hızlı olduğunu söyledi. Kod açık niyet, optimize edici derleyici oynamaya çalışmayın. Performans için yalnızca belirli bir durumda bir sorun olarak ölçüldüğünde kodlayın.
Cameron Lowell Palmer

5
Size katılmama izin verin. Objective-C'de 'yaratmadığınız bir şeye güçlü bir referans tutmak' her zaman olur. Bu yüzden tek bir sahip yerine referans sayımı vardır . Bu öneriyi yedeklemek için referansınız var mı? Lütfen zayıf çıkışların diğer faydalarını listeleyebilir misiniz?
kjam

4
İşte cevap geliştiricisinde
petrsyn

450

UYARI, ESKİ CEVAP : Bu cevap WWDC 2015'e göre güncel değildir, doğru cevap için yukarıdaki kabul edilen cevaba (Daniel Hall) bakın. Bu cevap kayıt için kalacaktır.


Özetle geliştirici kütüphanesinden :

Pratik bir bakış açısından, iOS ve OS X çıkışlarında bildirilen özellikler olarak tanımlanmalıdır. Çıkışlar genellikle Dosya Sahibinden güçlü olması gereken bir uç dosyasındaki (veya iOS'ta bir storyboard sahnesindeki) üst düzey nesnelere olanlar dışında zayıf olmalıdır. Bu nedenle, oluşturduğunuz çıkışlar varsayılan olarak zayıf olacaktır, çünkü:

  • Örneğin, bir görünüm denetleyicisinin görünümünün veya bir pencere denetleyicisinin penceresinin alt görünümlerinde oluşturduğunuz çıkışlar, sahiplik anlamına gelmeyen nesneler arasındaki rastgele başvurulardır.

  • Güçlü çıkışlar genellikle çerçeve sınıfları tarafından belirtilir (örneğin, UIViewController'ın görünüm çıkışı veya NSWindowController'ın pencere çıkışı).

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

10
Apple doc sayfasının belirli bir bölümüne atlamak için "geliştirici kitaplığı" bağlantısını nasıl aldınız? Apple dokümanlarına her bağladığımda, her zaman sayfanın üst kısmına bağlanır (ilgilenilen içerik sayfanın yarısında olsa bile). Teşekkürler.
bearMountain

68
Bağlantıyı soldaki gezinme bölmesinden kopyaladım. : D
Alexsander Akers

27
"Dosya Sahibinden bir uç dosyasındaki en üst düzey nesnelere (veya iOS'ta bir film şeridi sahnesine olanlar hariç) ne anlama gelir?
Van Du Tran

16
@VanDuTran - NIB'de kök düzeyinde olan nesneler anlamına gelir, yani orada doğrudan ana görünümün bir alt görünümü olmayan başka bir görünüm başlattığınızı, o zaman güçlü bir referansa sahip olması gerektiğini söyleyin.
mattjgalloway

6
Üst seviye, uca baktığınızda, nesnenin soldaki listede göründüğü anlamına gelir. Hemen hemen tüm uçların içinde bir UIView vardır - bu tek üst düzey nesne olabilir. Başka öğeler eklerseniz ve listede gösterilirlerse, bunlar "üst düzey nesnelerdir"
David H

50

Belgeler alt weakgörünümler için özelliklerin kullanılmasını önermekle birlikte, iOS 6'dan beri strongbunun yerine (varsayılan sahiplik niteleyicisi) iyi görünmektedir . Bu, UIViewControllerartık görünümlerdeki değişimin artık kaldırılmamasından kaynaklanıyor.

  • İOS 6'dan önce, denetleyicinin görünümünün alt görünümlerine güçlü bağlantılar tuttuysanız, görünüm denetleyicisinin ana görünümü kaldırılırsa, görünüm denetleyicisi etrafta olduğu sürece alt görünümlere tutunur.
  • İOS 6'dan bu yana, görünümler artık kaldırılmıyor, ancak bir kez yüklendi ve daha sonra denetleyicileri olduğu sürece yapışıyor. Bu yüzden güçlü özellikler önemli değil. Ayrıca güçlü referans grafiğini gösterdiğinden güçlü referans döngüleri oluşturmazlar.

Bununla birlikte, kullanma arasında parçalandım dedi

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

ve

@property (nonatomic) IBOutlet UIButton *button;

iOS 6 ve sonrasında:

  • weakAçıkça kullanıldığında , denetleyicinin düğmenin sahipliğini istemediğini belirtir.

  • Ancak weak, iOS 6'da görüntüleme boşaltma olmadan atlamak zarar vermez ve daha kısadır. Bazıları da daha hızlı olduğunu işaret edebilir, ancak henüz weak IBOutlets nedeniyle çok yavaş bir uygulama ile karşılaşmadım .

  • Kullanmamak weakbir hata olarak algılanabilir.

Alt satır: iOS 6'dan beri, görünüm boşaltma özelliğini kullanmadığımız sürece bunu yanlış anlayamayız. Parti zamanı. ;)


Bu doğrudur, ancak yine de görünümü kendiniz kaldırmak isteyebilirsiniz. Bu durumda, tüm çıkışlarınızı nilmanuel olarak ayarlamanız gerekir.
hypercrypt

PS: weakARM64'te biraz daha ucuz: D
hypercrypt

Bu, görünüm boşaltma uygularsanız, weaközellikler veya __weakörnek değişkenler gitmek için doğru yoldur. Sadece burada daha az hata potansiyeli olduğunu belirtmek istedim. weakArm64'te daha ucuz olmak için , armv7'de weak IBOutlets ile gerçek bir performans sorunu bile görmedim . :)
Tammo Freese

Bu durumda strongda mantıklı. strongyalnızca görünüm boşaltmayı kullanırsanız zararlıdır, ancak bu günlerde kim kullanıyor? :)
Tammo Freese

2
@Rocotilos İlk iPhone'un çok sınırlı bir RAM'i vardı. Doğru hatırlıyorsam, 128 MB, etkin uygulama için yaklaşık 10 MB bırakıyor. Küçük bir bellek ayak izine sahip olmak çok önemliydi, bu yüzden görünüm boşaltıldı. Artık daha fazla RAM'e ve Apple'ın iOS 6'da UIViews'i optimize ettiği için bu değişti, böylece bellek uyarılarında, görünümü boşaltmadan çok fazla bellek serbest bırakılabilir.
Tammo Freese

34

Bununla ilgili bir sorun görmüyorum. ARC öncesi, IBOutlets'imi her zaman yaptım assign, çünkü onlar zaten gözetimleri tarafından korunuyorlar. Bunları yaparsanız weak, size işaret olarak, viewDidUnload onları dışarı nil zorunda olmamalıdır.

Bir uyarı: Bir ARC projesinde iOS 4.x'i destekleyebilirsiniz, ancak yaparsanız kullanamazsınız weak, bu yüzden bunları yapmanız gerekir assign, bu durumda viewDidUnloadönlemek için başvuruyu sıfırlamak istersiniz. sarkan bir işaretçi. İşte yaşadığım sarkan bir işaretçi hatası örneği:

Bir UIViewController posta kodu için bir UITextField'a sahiptir. Kullanıcının konumunu coğrafi olarak kodlamak ve posta kodunu ayarlamak için CLLocationManager'ı kullanır. İşte temsilci geri araması:

-(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];
}

Bu görüşü doğru zamanda reddettiysem ve self.zip girmediysem viewDidUnload, temsilci geri aramasının self.zip.text'e kötü bir erişim istisnası atabileceğini buldum.


4
Anladığım kadarıyla, weakmülklerin yenilenmesi gerekmiyor viewDidUnload. Peki Apple'ın satış noktası oluşturma şablonu neden bir [self setMySubview:nil]?
Yang Meyer

3
IBOutlet'iniz için güçlü / tutulan kullanımın soruna neden olabileceği gerçek dünya vakaları var mı? Yoksa sadece gereksiz bir koruma mı, kötü kodlama stili anlamına gelir, ancak kodunuzu etkilemez mi?
Enzo Tran

1
Fazlalık tutma olarak bir şey var mı? Fazladan bir alıkonma varsa, bunun düzgün sayılmamasına neden olur ve bu nedenle alıkonma sayısında fazladan bir alıkonma olduğu için olabildiğince çabuk serbest bırakılmaz.
karlbecker_com

25

IBOutletperformans açısından güçlü olmalı. Bkz Film Şeridi başvurusu, güçlü IBOutlet, IOS Sahne dock 9

Bu paragrafta açıklandığı gibi, görünüm denetleyicisinin görünümünün alt görünümleri için çıkışlar zayıf olabilir, çünkü bu alt görünümler zaten uç dosyasının üst düzey nesnesine aittir. Ancak, bir Çıkış zayıf bir işaretçi olarak tanımlandığında ve işaretçi ayarlandığında, ARC çalışma zamanı işlevini çağırır:

id objc_storeWeak(id *object, id value);

Bu, nesne değerini anahtar olarak kullanarak işaretçiyi (nesne) bir tabloya ekler. Bu tabloya zayıf tablo denir. ARC bu tabloyu uygulamanızın tüm zayıf işaretlerini saklamak için kullanır. Şimdi, nesne değeri yeniden konumlandırıldığında, ARC zayıf tablo üzerinden yinelenecek ve zayıf referansı nil değerine ayarlayacaktır. Alternatif olarak, ARC şunları arayabilir:

void objc_destroyWeak(id * object)

Ardından, nesne kayıtsız kalır ve objc_destroyWeak tekrar çağırır:

objc_storeWeak(id *object, nil)

Zayıf bir referansla ilişkilendirilen bu defter tutma, güçlü bir referansın yayınlanmasından 2-3 kat daha uzun sürebilir. Bu nedenle, zayıf bir referans, çıkışları güçlü olarak tanımlayarak kaçınabileceğiniz çalışma zamanı için bir ek yük getirir.

Xcode 7'den itibaren, strong

WWDC 2015 oturumu 407 Arayüz Oluşturucu'da UI Tasarımlarını Uygulama'yı izlerseniz , ( http://asciiwwdc.com/2015/sessions/407 transkripti )

Ve belirtmek istediğim son seçenek, güçlü veya zayıf olabilen depolama türüdür.

Genel olarak çıkışınızı güçlü hale getirmelisiniz, özellikle de çıkışı bir alt görünüme veya her zaman görünüm hiyerarşisi tarafından korunmayacak bir kısıtlamaya bağlıyorsanız.

Bir çıkışı gerçekten zayıflatmanız için gereken tek zaman, görünüm hiyerarşisini yedekleyen bir şeye başvuran ve genel olarak önerilmeyen özel bir görünümünüz varsa.

Bu yüzden güçlü seçeceğim ve çıkışımı oluşturacak bağlantıya tıklayacağım.


1
Gerçek nedeni açıklayan büyük cevap -neden-
micnguyen

Bu iyi bir şey ama ben storyboard uygulanan jest tanıyıcı gelen sızıntılar gördüm.
thibaut noah

1
Bu çizgiyi anlayamıyorum. "Bir çıkışı gerçekten zayıflatmanız için gereken tek zaman, görünüm hiyerarşisini destekleyen bir şeye referans veren özel bir görünümünüz varsa ve genel olarak önerilmez." Örnek var mı?
user1872384

Zayıf ve güçlü olan deinit zamanı hesapladım ve tamamen aynı.
touti

Ama hızlı bir şekilde bu daha doğru. Zayıf referanslar daha hızlıdır.
thesummersign

20

İOS geliştirmede NIB yüklemesi Mac geliştirmeden biraz farklıdır.

Mac geliştirmede bir IBOutlet genellikle zayıf bir referanstır: NSViewController alt sınıfınız varsa yalnızca üst düzey görünüm korunur ve denetleyiciyi serbest bıraktığınızda tüm alt görünümleri ve çıkışları otomatik olarak serbest bırakılır.

UiViewController çıkışları güçlü referanslar kullanarak ayarlamak için Anahtar Değer Kodlamasını kullanır. Bu yüzden UIViewController'ınızı serbest bıraktığınızda, üst görünüm otomatik olarak serbest bırakılır, ancak dealloc yöntemindeki tüm çıkışlarını da yeniden ayırmanız gerekir.

Büyük Nerd Çiftliği'nden gelen bu yazıda, bu konuyu ele alıyorlar ve ayrıca IBOutlet'te güçlü bir referans kullanmanın neden iyi bir seçim olmadığını açıklıyorlar (bu durumda Apple tarafından önerilse bile).


16
2009'da olduğu gibi açıklıyor. ARC ile bu önemli ölçüde değişti.
Dafydd Williams

1
:( Big Nerd Ranch bağlantısı öldü ... yine de okumam gerekiyor. Herkes bu yazı hakkında daha fazla ayrıntı biliyor, bu yüzden bulabilir miyim?
Motti Shneor

@MottiShneor endişelenmeyin, bağlantı ARC'den yaklaşık kez önce olduğu ve artık alakalı olmadığı için önemli değil.
Sergey Grischyov

18

Burada belirtmek istediğim bir şey var, bu da Apple mühendislerinin kendi WWDC 2015 videolarında söylediklerine rağmen:

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

Apple konu hakkındaki düşüncelerini değiştirmeye devam ediyor, bu da bize bu sorunun tek bir doğru cevabı olmadığını söylüyor. Apple mühendislerinin bile bu konuda bölünmüş olduğunu göstermek için, Apple'ın en son örnek koduna bir göz atın ve bazı kişilerin zayıf kullandığını ve bazılarının kullanmadığını göreceksiniz.

Bu Apple Pay örneği zayıf kullanır: https://developer.apple.com/library/ios/samplecode/Emporium/Listings/Emporium_ProductTableViewController_swift.html#//apple_ref/doc/uid/TP40016175-Emporium_ProductTableViewController_swift-Dit8

Bu resim içinde resim örneği gibi: https://developer.apple.com/library/ios/samplecode/AVFoundationPiPPlayer/Listings/AVFoundationPiPPlayer_PlayerViewController_swift.html#//apple_ref/doc/uid/TP40016166-AVFoundationPiPlerPlayerPlayerPlayerPlayer

Lister örneğinde olduğu gibi: https://developer.apple.com/library/ios/samplecode/Lister/Listings/Lister_ListCell_swift.html#//apple_ref/doc/uid/TP40014701-Lister_ListCell_swift-DontLinkElementID_57

Temel Konum örneğinde olduğu gibi: https://developer.apple.com/library/ios/samplecode/PotLoc/Listings/Potloc_PotlocViewController_swift.html#//apple_ref/doc/uid/TP40016176-Potloc_PotlocViewController_swift.html#//apple_ref/doc/uid/TP40016176-Potloc_PotlocViewController_swift-DontLinkElementID_6

Görünüm denetleyicisi önizleme örneğinde olduğu gibi: https://developer.apple.com/library/ios/samplecode/ViewControllerPreviews/Listings/Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_swift.html#//apple_ref/doc/uid/TP40016546_viewDoire_PreDu_UzayDogu_UzakDurum_UzakDurum_UzakDurum_Gid

HomeKit örneğinde olduğu gibi: https://developer.apple.com/library/ios/samplecode/HomeKitCatalog/Listings/HMCatalog_Homes_Action_Sets_ActionSetViewController_swift.html#//apple_ref/doc/uid/TP40015048-HMatata_At_At_At_At_At_At_At_At_Az

Tüm bunlar iOS 9 için tamamen güncellenir ve hepsi zayıf çıkışlar kullanır. Buradan öğrendik. A. Sorun, bazı insanların ortaya çıkardığı kadar basit değil. Apple tekrar tekrar fikrini değiştirdi ve C. Sizi mutlu eden her şeyi kullanabilirsiniz :)

Bana bu cevabın açıklamasını ve referanslarını veren Paul Hudson'a (www.hackingwithsift.com'un yazarı) özel teşekkürler.

Umarım bu konu biraz daha iyi anlaşılır!

Kendine iyi bak.


Bu konuyu bir süredir kontrol ediyorum ve somut cevaplar bulamadım. Yukarıdaki bağlantı, her ikisinin de iyi olduğunu ve genel olarak Xcode'un otomatik olarak önerdiği şeylerle gittiğini öne sürdüğünden.
subin272



5

Görünüşe göre yıllar içinde bir şeyler değişti ve şimdi Apple genel olarak güçlü kullanılmasını öneriyor. WWDC oturumlarına ilişkin kanıtlar, oturum Oluşturucu'da UI Tasarımlarını Uygulama 407'de başlar ve saat 32: 30'da başlar. Söylediklerinden notum (neredeyse, tam olarak değilse, alıntı yapıyor):

  • genel olarak çıkış bağlantıları, özellikle görünüm hiyerarşisi tarafından her zaman korunmayan bir alt görünüm veya kısıtlama bağlarsak güçlü olmalıdır

  • görünüm hiyerarşisinde yedeklenen bir şeye referans veren özel görünümler oluştururken zayıf çıkış bağlantısı gerekebilir ve genel olarak önerilmez

Diğer servislerde, özel görünümümüzün bir kısmı görünüm hiyerarşisindeki bazı görünümlerle bir tutma döngüsü oluşturmadığı sürece şimdi her zaman güçlü olmalıdır.

DÜZENLE :

Bazıları soruyu sorabilir. Güçlü bir referansla tutulması, kök görünüm denetleyicisi ve sahip olma görünümü referansı koruduğu için bir tutma döngüsü oluşturmuyor mu? Ya da bu neden değişti? Bence uçlar xib'den nasıl yaratıldıklarını anlattıklarında cevap bu konuşmada daha erken. Bir VC ve görünüm için ayrı bir uç oluşturulmuştur. Bence tavsiyeleri değiştirmelerinin nedeni bu olabilir. Yine de Apple'dan daha derin bir açıklama almak iyi olurdu.


4

En önemli bilginin şu olduğunu düşünüyorum: xib'deki öğeler otomatik olarak alt görünümlerde. Alt görünümler NSArray. NSArray öğelerinin sahibidir. vs güçlü yönleri vardır. Çoğu durumda başka bir güçlü işaretçi (IBOutlet) oluşturmak istemezsiniz.

Ve ARC ile hiçbir şey yapmanıza gerek yok viewDidUnload

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.