Czy IBOutlets powinien być silny czy słaby pod łukiem?

[10]}rozwijam wyłącznie dla iOS 5 używając ARC. Czy IBOutletS do UIView s (i podklasy) powinny być strong Czy weak?

Następujące:

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

Pozbyłby się tego wszystkiego:

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

Czy są jakieś problemy z zrobieniem tego? Szablony używają strong, podobnie jak Automatycznie generowane właściwości tworzone podczas łączenia się bezpośrednio z nagłówkiem z edytora 'Interface Builder' , ale dlaczego? UIViewController ma już strong odniesienie do swojego view, który zachowuje swoje podglądy.

Author: Julian Król, 2011-10-06

11 answers

Obecnie zalecaną najlepszą praktyką firmy Apple jest to, aby IBOutlets był silny, chyba że słaby jest szczególnie potrzebny, aby uniknąć cyklu zatrzymywania. Jak wspomniano powyżej, zostało to skomentowane w sesji "Implementing UI Designs in Interface Builder" z WWDC 2015, gdzie inżynier Apple powiedział: {]}

I ostatnią opcją, którą chcę zwrócić uwagę, jest typ pamięci, który może bądź silny albo słaby. Ogólnie rzecz biorąc, powinieneś zrobić swój outlet mocna, zwłaszcza jeśli podłączasz gniazdo do subview lub do ograniczenie, które nie zawsze będzie utrzymywane przez Widok hierarchia. Jedyny czas, kiedy naprawdę trzeba zrobić gniazdko słabe jest, jeśli masz niestandardowy widok, który odwołuje się do czegoś z kopii zapasowej widoku hierarchii i w ogóle nie jest to zalecane.

Zapytałem o to na Twitterze inżyniera z zespołu IB i potwierdził, że strong powinno być domyślne i że dokumenty deweloperskie są aktualizacja.

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

 194
Author: Daniel Hall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-17 17:12:59

Uwaga, nieaktualna odpowiedź : ta odpowiedź nie jest aktualna zgodnie z WWDC 2015, poprawna odpowiedź znajduje się w accepted answer (Daniel Hall) powyżej. Ta odpowiedź zostanie zapisana.


Podsumowanie z biblioteki programistów:

Z praktycznego punktu widzenia, w systemach iOS i OS X powinny być zdefiniowane jako Deklarowane właściwości. Gniazda powinny być generalnie słabe, z wyjątkiem tych od właściciela pliku do obiektów najwyższego poziomu w pliku nib (lub, w iOS scena storyboard), która powinna być silna. Punkty, które tworzysz, będą więc domyślnie słabe, ponieważ:

  • Punkty wyjściowe, które tworzy się na przykład w podglądzie widoku kontrolera widoku lub okna kontrolera okna, są arbitralnymi odniesieniami między obiektami, które nie implikują własności.

  • Mocne wyjścia są często określane przez klasy framework (na przykład ujście widoku Uiviewcontrollera lub Nswindowcontrollera wylot okienny).

    @property (weak) IBOutlet MyView *viewContainerSubview;
    @property (strong) IBOutlet MyOtherClass *topLevelObject;
    
 445
Author: Alexsander Akers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-11 14:45:04

Podczas gdy dokumentacja zaleca używanie weak na właściwościach w podwidywaniach, od iOS 6 wydaje się być w porządku używać strong (domyślnego kwalifikatora własności) zamiast tego. jest to spowodowane zmianą w UIViewController, że widoki nie są już rozładowywane.

  • Przed iOS 6, jeśli utrzymałeś silne linki do podglądów podglądu kontrolera, jeśli główny widok kontrolera został rozładowany, będą one trzymać się podglądów tak długo, jak kontroler widoku jest w pobliżu.
  • od iOS 6 widoki nie są już rozładowywane, ale ładowane raz, a następnie pozostają w pobliżu tak długo, jak jest tam ich kontroler. Tak silne właściwości nie będą miały znaczenia. Nie będą również tworzyć silnych cykli odniesienia, ponieważ wskazują silny Wykres odniesienia.

To powiedziawszy, jestem rozdarty między używaniem

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

I

@property (nonatomic) IBOutlet UIButton *button;

W iOS 6 i po:

  • Użycie weak jasno stwierdza, że kontroler nie chce mieć własności guzik.

  • Ale pominięcie weak nie zaszkodzi w iOS 6 bez rozładowania widoku i jest krótsze. Niektórzy mogą zauważyć, że jest również szybszy, ale jeszcze nie spotkałem się z aplikacją, która jest zbyt wolna z powodu weak IBOutlets.

  • Nieużywanie weak może być postrzegane jako błąd.

Podsumowując: od iOS 6 nie możemy już tego źle zrozumieć, dopóki nie używamy rozładowywania widoku. Czas na imprezę. ;)

 46
Author: Tammo Freese,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-26 08:32:33

Nie widzę w tym żadnego problemu. Pre-ARC, zawsze robiłem moje Iboutlety assign, ponieważ są już zachowane przez ich superwizje. Jeśli je tworzysz weak, nie powinieneś ich usuwać w viewDidUnload, jak to podkreślasz.

Jedno zastrzeżenie: możesz obsługiwać iOS 4.x w projekcie ARC, ale jeśli to zrobisz, nie możesz użyć weak, więc musisz je utworzyć assign, w którym to przypadku nadal chcesz zerować odniesienie w viewDidUnload, aby uniknąć zwisającego wskaźnika. Oto przykład zwisającego wskaźnika bug, którego doświadczyłem:

UIViewController ma pole UITextField dla kodu pocztowego. Używa CLLocationManager do odwrócenia geocode lokalizacji użytkownika i ustawić kod pocztowy. Oto odpowiedź delegata:

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

Stwierdziłem, że jeśli odrzucę ten pogląd we właściwym czasie i nie zeruję siebie.zip w viewDidUnload, wywołanie zwrotne delegata może rzucić zły wyjątek dostępu na siebie.zip.tekst.

 34
Author: Christopher Pickslay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-11 16:01:41

W rozwoju iOS Ładowanie NIB trochę różni się od rozwoju Maca.

W rozwoju komputerów Mac IBOutlet jest zwykle słabym punktem odniesienia: jeśli masz podklasę NSViewController, tylko widok najwyższego poziomu zostanie zachowany, a gdy wyłączysz kontroler, wszystkie jego Podglądy i wyjścia zostaną automatycznie zwolnione.

UiViewController używa kodowania wartości klucza do ustawiania gniazd przy użyciu silnych referencji. Więc po dealloc UIViewController, widok z góry będzie automatycznie deallocated, ale musisz również deallocate wszystkie jego wyloty w metodzie dealloc.

W tym poście z Big Nerd Ranch omawiają ten temat, a także wyjaśniają, dlaczego używanie silnego odniesienia w IBOutlet nie jest dobrym wyborem (nawet jeśli jest to zalecane przez Apple w tym przypadku).

 20
Author: Giuseppe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-30 16:30:19

IBOutlet powinien być silny, ze względu na wydajność. Zobacz Storyboard Reference, Strong IBOutlet, Scene Dock w iOS 9

Jak wyjaśniono w tym ustępie, punkty wyjścia do podglądu widok kontrolera może być słaby, ponieważ te podglądy są już należy do najwyższego poziomu obiektu pliku nib. Jednak, gdy wylot jest zdefiniowany jako słaby wskaźnik i wskaźnik jest ustawiony, Arc wywołuje funkcja runtime:

id objc_storeWeak(id *object, id value);

To dodaje pointer (object) do tabeli wykorzystującej wartość obiektu jako klucz. Ta tabela jest zwany słabym stołem. ARC używa tej tabeli do przechowywania wszystkich słabe punkty Twojej aplikacji. Teraz, gdy wartość obiektu jest dealokowany, łuk będzie powtarzał się nad słabym stołem i ustawiał słabe odniesienie do nil. Alternatywnie ARC może wywołać:

void objc_destroyWeak(id * object)

Wtedy obiekt jest niezarejestrowani i objc_destroyWeak ponownie wywołują:

objc_storeWeak(id *object, nil)

Ta księgowość powiązane ze słabym odniesieniem może trwać 2-3 razy dłużej nad wydaniem mocne odniesienie. Słaba Referencja wprowadza więc narzut dla runtime, którego można uniknąć, po prostu definiując outlety jako silne.

Od Xcode 7 sugeruje strong

Jeśli oglądasz WWDC 2015 session 407 Implementowanie projektów interfejsu użytkownika w Interface Builder , sugeruje (transkrypcja z http://asciiwwdc.com/2015/sessions/407 )

Oraz ostatnią opcją, na którą chcę zwrócić uwagę, jest typ pamięci, który może być silny lub słaby.

Ogólnie rzecz biorąc, powinieneś wzmocnić swoje gniazdko, zwłaszcza jeśli podłączasz gniazdo do podglądu podrzędnego lub ograniczenia, które nie zawsze będą zachowywane przez hierarchię widoku.

Jedyny raz, kiedy naprawdę potrzebujesz osłabić punkt wyjściowy, to jeśli masz niestandardowy widok, który odwołuje się do czegoś w hierarchii widoku i ogólnie nie jest to zalecane.

Więc wybieram strong i klikam connect co wygeneruje mój outlet.

 14
Author: onmyway133,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-17 09:40:43

Jedną rzecz chciałbym tutaj podkreślić, a mianowicie, pomimo tego, co inżynierowie Apple stwierdzili w swoim własnym filmie WWDC 2015 tutaj:

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

Apple ciągle zmienia zdanie na ten temat, co mówi nam, że nie ma jednej prawidłowej odpowiedzi na to pytanie. Aby pokazać, że nawet inżynierowie Apple są podzieleni w tym temacie, spójrz na najnowszą przykładowy kod, a zobaczysz, że niektórzy używają słabych, a niektórzy nie.

Ten przykład Apple Pay wykorzystuje słabe: https://developer.apple.com/library/ios/samplecode/Emporium/Listings/Emporium_ProductTableViewController_swift.html#//apple_ref/doc/uid/TP40016175-Emporium_ProductTableViewController_swift-DontLinkElementID_8

Podobnie jak to picture-in-picture przykład: https://developer.apple.com/library/ios/samplecode/AVFoundationPiPPlayer/Listings/AVFoundationPiPPlayer_PlayerViewController_swift.html#//apple_ref/doc/uid/TP40016166-AVFoundationPiPPlayer_PlayerViewController_swift-DontLinkElementID_4

Podobnie jak Przykład Listera: https://developer.apple.com/library/ios/samplecode/Lister/Listings/Lister_ListCell_swift.html#//apple_ref/doc/uid/TP40014701-Lister_ListCell_swift-DontLinkElementID_57

Podobnie jak Przykład Lokalizacji rdzenia: https://developer.apple.com/library/ios/samplecode/PotLoc/Listings/Potloc_PotlocViewController_swift.html#//apple_ref/doc/uid/TP40016176-Potloc_PotlocViewController_swift-DontLinkElementID_6

Podobnie jak podgląd kontrolera widoku przykład: https://developer.apple.com/library/ios/samplecode/ViewControllerPreviews/Listings/Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_swift.html#//apple_ref/doc/uid/TP40016546-Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_swift-DontLinkElementID_5

Podobnie jak HomeKit przykład: 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-DontLinkElementID_23

Wszystkie są w pełni zaktualizowane dla iOS 9, a wszystkie korzystają ze słabych punktów. Z tego dowiadujemy się, że A. problem nie jest tak prosty, jak niektórzy ludzie sprawiają, że jest. B. Apple wielokrotnie zmieniało zdanie, A C. możesz użyć cokolwiek cię uszczęśliwi:)

Specjalne podziękowania dla Paula Hudsona (autora www.hackingwithsift.com), który udzielił mi wyjaśnień i referencji do tej odpowiedzi.

Mam nadzieję, że to trochę lepiej wyjaśni temat!

Trzymaj się.

 11
Author: syedfa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-05 21:25:41

Od WWDC 2015 jest sesja na Implementowanie projektów interfejsu użytkownika w Interface Builder . Wokół znaku 32min mówi, że zawsze chcesz, aby Twoje @IBOutlet strong .

 9
Author: Johannes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-09 13:11:03

Bądź świadomy, IBOutletCollection powinien być @property (strong, nonatomic).

 6
Author: landonandrey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-25 13:02:53

Wygląda na to, że coś się zmieniło przez lata i teraz Apple zaleca stosowanie strong w ogóle. Dowody na ich sesję WWDC są w sesji 407 - Implementing UI Designs in Interface Builder i zaczyna się o 32: 30. Moja notka z tego co mówi to (prawie, jeśli nie do końca, cytuję GO):

  • połączenia wylotowe w ogóle powinny być silne, zwłaszcza jeśli podłączymy subview lub ograniczenie, które nie zawsze jest utrzymywane przez widok hierarchia

  • słabe połączenie gniazdka może być potrzebne podczas tworzenia niestandardowych widoków, które mają odniesienie do czegoś z kopii zapasowej w hierarchii widoku i ogólnie nie jest to zalecane

W innych oddziałach powinno być teraz zawsze silne, o ile niektóre z naszych niestandardowych widoków nie tworzą cyklu zachowywania z niektórymi z widoków w hierarchii widoków

EDIT:

Niektórzy mogą zadać pytanie. Czy utrzymanie go z silnym odniesienie nie tworzy cyklu zachowywania, ponieważ kontroler widoku głównego i widok posiadania zachowują odniesienie do niego? Albo dlaczego to się zmieniło? Myślę, że odpowiedź jest wcześniej w tej rozmowie, kiedy opisują, w jaki sposób stalówki są tworzone z xib. Istnieje oddzielna stalówka stworzona dla VC i dla widoku. Myślę, że to może być powód, dla którego zmieniają zalecenia. Mimo to byłoby miło uzyskać głębsze Wyjaśnienie od Apple.

 5
Author: Julian Król,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-07 09:01:46

Myślę, że najważniejsze informacje to: Elementy w xib są automatycznie w podglądzie widoku. Subviews to NSArray. NSArray jest właścicielem jego elementów. itp mają silne wskazówki na nich. Więc w większości przypadków nie chcesz tworzyć innego silnego wskaźnika (IBOutlet)

A Z ARC nie musisz nic robić w viewDidUnload

 4
Author: kraag22,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-04 14:49:28