2013-06-24 6 views
11

Ostatnio pisałem jakiś kod, gdzie starał się odnosić do gniazdka na UIViewController ja właśnie tworzony z [storyboard instantiateViewControllerWithIdentifier] i modyfikować podrzędny że wylot wskazywanego przed przedstawieniem ViewController. Nie zadziałało, ponieważ widok ViewController nie załadował jeszcze swoich subviews, w tym ten, do którego nawiązał mój adres, więc własność właśnie dała mi zerowy wskaźnik.Clean sposobem na widok wymusić załadowanie subviews wczesne

Po (z jakiejś walki) tropienia przyczynę mojego problemu w debugger, I Googled wokół i dowiedział się, poprzez odpowiedzi jak this one, że mogę spowodować pogląd załadować jego subviews bez wyświetlania poprzez wywołanie myViewController.view getter . Potem mogę bez problemu uzyskać dostęp do mojego gniazdka.

To jasne hack, choć i Xcode - całkiem słusznie - nie podoba, i gniewnie protestuje z tego ostrzeżenia:

Property wynik dostęp nieużywany - getters nie powinny być wykorzystywane do działań niepożądanych

Czy istnieje nie-hacky alternatywny sposób na zrobienie tego, który nie ma wpływu na zdobywcę .view? Alternatywnie, czy istnieją kanoniczne/idiomatyczne wzorce dla tego scenariusza, obejmujące coś w rodzaju dynamicznego dodawania programu obsługi do wywołania, gdy tylko ładowane są subviews?

Czy jest to standardowe rozwiązanie tylko po to, aby zamienić myViewController.view na [myViewController view], aby zamknąć ostrzeżenie Xcode'a, a następnie żyć z hackerem?

+0

można zmienić dowolny OBJ. właściwość [właściwość obj], aby zatrzymać to ostrzeżenie. Nie ma różnicy między geterem ObjC a selektorem bez argumentów. –

Odpowiedz

25

iOS 9 lub nowszy, można użyć:

viewController.loadViewIfNeeded() 

Dokumenty: https://developer.apple.com/reference/uikit/uiviewcontroller/1621446-loadviewifneeded

+0

To jest odpowiedź, która najbardziej bezpośrednio odpowiada na zadane pytanie i dostaje mój znacznik wyboru, ale zauważ, że w wielu przypadkach może to być błędne - rozważ [przeniesienie jakiejkolwiek logiki, której potrzebujesz, widok załadowany do 'viewDidLoad'] (http: // stackoverflow .com/a/18172365/1709587) zamiast tego. –

+0

@MarkAmery Może, ale nie musi. :) –

-1

Możesz zadzwonić pod numer [myViewController loadView], aby jawnie załadować widok, zamiast nadużywać programu pobierającego .view. Użytkownik pobierający .view faktycznie wywołuje loadView, jeśli jest to konieczne, po wywołaniu.

To nie jest jeszcze bardzo ładne rozwiązanie, ponieważ Sekcja UIView Documentation „s na loadView wyraźnie poucza, że ​​

Nigdy nie powinno wywołać tę metodę bezpośrednio

+0

Źródło: zbMax dla tej odpowiedzi; opublikował to jako komentarz, ale jest to kompletna odpowiedź na to pytanie. –

1

Jeśli rozumiem zostanie poprawnie, myślę istnieje inne, dość standardowe rozwiązanie: przenieś kod modyfikacji/konfiguracji gniazdka do metody viewDidLoad (ostatnio utworzonego VC).

Temat jest również omawiany w tej publikacji: question.

Wymagałoby to pewnej restrukturyzacji, ale może dać ci "czystszy" projekt pod względem MVC, jeśli twój przychodzący VC obsługiwałby własną konfigurację, i unikałaby "Nigdy nie nazwij tej metody bezpośrednio" zwężenia na loadView .

+0

D'oh. Tak, powinienem to robić przez cały czas. –

+0

Chociaż czytałem sprzeczne twierdzenia o tym, czy 'viewDidLoad' może być wywołana więcej niż raz - warto może mieć w' BOOL isInitialized' ivar, który jest używany do zapewnienia, że ​​kod inicjowania w 'viewDidLoad' jest tylko kiedykolwiek wykonywane jeden raz (Jeśli to konieczne). –

6

Zgadzam się, że wymuszanie załadowania widoku powinno być unikane, ale natknąłem się na przypadek, w którym wydawało się to jedynym rozsądnym rozwiązaniem problemu (pojawienie się kontrolera UINavigationController zawierającego kontroler UISearch, który jeszcze nie został wywołany powoduje, że nieprzyjemna konsola mówi ostrzeżenie).

Użyłem nowego API iOS9 loadViewIfNeeded, a dla wersji wcześniejszej iOS9 viewController.view.alpha = 1.0. Oczywiście dobry komentarz powyżej tego kodu uniemożliwi Tobie (lub komuś innemu) usunięcie tego kodu później, myśląc, że jest niepotrzebny.

Fakt, że Apple dostarcza teraz ten API, sygnalizuje, że może być potrzebny od czasu do czasu.

2

połączyły odpowiedzi Rudolph/Swany dla pre ios9 rozmieszczenia skierowany

if #available(iOS 9.0, *) { 
     loadViewIfNeeded() 
    } 
    else { 
     // _ = self.view works but some Swift compiler genius could optimize what seems like a noop out 
     // hence this perversion from this recipe http://stackoverflow.com/questions/17279604/clean-way-to-force-view-to-load-subviews-early 
     view.alpha = 1 
    }