Czy istnieje wbudowany sposób na przejście od a UIView
do jego UIViewController
? Wiem, że możesz dostać się UIViewController
do jego UIView
poprzez, [self view]
ale zastanawiałem się, czy istnieje odwrotne odniesienie?
źródło
Czy istnieje wbudowany sposób na przejście od a UIView
do jego UIViewController
? Wiem, że możesz dostać się UIViewController
do jego UIView
poprzez, [self view]
ale zastanawiałem się, czy istnieje odwrotne odniesienie?
Ponieważ od dawna jest to odpowiedź zaakceptowana, uważam, że muszę ją poprawić, podając lepszą odpowiedź.
Kilka uwag na temat potrzeby:
Oto przykład jego wdrożenia:
@protocol MyViewDelegate < NSObject >
- (void)viewActionHappened;
@end
@interface MyView : UIView
@property (nonatomic, assign) MyViewDelegate delegate;
@end
@interface MyViewController < MyViewDelegate >
@end
Widok łączy się z jego delegatem (jak UITableView
na przykład) i nie obchodzi go, czy został zaimplementowany w kontrolerze widoku, czy w jakiejkolwiek innej klasie, której używasz.
Moja pierwotna odpowiedź brzmi: nie polecam tego, ani pozostałych odpowiedzi, w których uzyskano bezpośredni dostęp do kontrolera widoku
Nie ma wbudowanego sposobu, aby to zrobić. Chociaż można obejść przez dodanie IBOutlet
na UIView
i łączenia ich w konstruktorze Interface, nie jest to zalecane. Widok nie powinien wiedzieć o kontrolerze widoku. Zamiast tego należy postępować zgodnie z sugestią @Phil M. i utworzyć protokół, który będzie używany jako delegat.
Korzystając z przykładu opublikowanego przez Brocka, zmodyfikowałem go tak, aby był to kategoria UIView zamiast UIViewController i sprawiłem, że będzie rekurencyjny, aby każdy podview mógł (mam nadzieję) znaleźć nadrzędny UIViewController.
Aby użyć tego kodu, dodaj go do nowego pliku klasy (nazwałem mój „UIKitCategories”) i usuń dane klasy ... skopiuj interfejs @ do nagłówka, a @implementation do pliku .m. Następnie w swoim projekcie #import „UIKitCategories.h” i użyj w kodzie UIView:
źródło
UIView
jest podklasąUIResponder
.UIResponder
określa metodę-nextResponder
z implementacją, która zwracanil
.UIView
zastępuje tę metodę, jak udokumentowano wUIResponder
(z jakiegoś powodu zamiast wUIView
) w następujący sposób: jeśli widok ma kontroler widoku, jest zwracany przez-nextResponder
. Jeśli nie ma kontrolera widoku, metoda zwróci podgląd.Dodaj to do swojego projektu i możesz rozpocząć.
Teraz
UIView
ma działającą metodę zwracania kontrolera widoku.źródło
UIView
a odbiorcąUIViewController
. Odpowiedź Phila M. obejmująca rekurencję to droga.Sugerowałbym bardziej lekkie podejście do przejścia przez cały łańcuch odpowiedzi bez konieczności dodawania kategorii w UIView:
źródło
Łącząc kilka już udzielonych odpowiedzi, wysyłam je również z moją implementacją:
Kategoria jest częścią mojej biblioteki statycznej z obsługą ARC , którą wysyłam do każdej tworzonej aplikacji. Został przetestowany kilka razy i nie znalazłem żadnych problemów ani wycieków.
PS: Nie musisz używać kategorii takiej jak ja, jeśli dany widok jest twoją podklasą. W tym drugim przypadku po prostu umieść metodę w swojej podklasie i możesz zacząć.
źródło
Chociaż technicznie można to rozwiązać zgodnie z zaleceniami pgb , IMHO, jest to jednak wada projektowa. Widok nie powinien być świadomy kontrolera.
źródło
I zmodyfikowane de odpowiedź więc mogę przekazać wszelkie widok, przycisk, etykiety itd., Aby uzyskać jej jednostki
UIViewController
. Oto mój kod.Edytuj wersję Swift 3
Edycja 2: - Szybkie rozszerzenie
źródło
Nie zapominaj, że możesz uzyskać dostęp do kontrolera widoku głównego dla okna, którego widok jest widokiem podrzędnym. Stamtąd, jeśli np. Używasz kontrolera widoku nawigacji i chcesz na niego nałożyć nowy widok:
Najpierw jednak musisz poprawnie ustawić właściwość rootViewController okna. Zrób to, gdy tworzysz kontroler po raz pierwszy, np. W aplikacji delegowanej:
źródło
[[self navigationController] view]
jest to „główny” (pod) widok okna,rootViewController
należy ustawić właściwość okna, która natychmiastnavigationController
kontroluje widok „główny”.Chociaż odpowiedzi te są technicznie poprawne, w tym Ushox, myślę, że zatwierdzonym sposobem jest wdrożenie nowego protokołu lub ponowne użycie istniejącego. Protokół izoluje obserwatora od obserwowanego, podobnie jak umieszczenie między nimi szczeliny na listy. W efekcie to właśnie robi Gabriel poprzez wywołanie metody pushViewController; widok „wie”, że właściwym protokołem jest grzeczne poproszenie twojego NavigationController o wypchnięcie widoku, ponieważ viewController jest zgodny z protokołem navigationController. Chociaż możesz stworzyć własny protokół, wystarczy skorzystać z przykładu Gabriela i ponownie użyć protokołu UINavigationController.
źródło
Natknąłem się na sytuację, w której mam mały komponent, którego chcę ponownie użyć, i dodałem trochę kodu w widoku wielokrotnego użytku (tak naprawdę to niewiele więcej niż przycisk otwierający a
PopoverController
).Chociaż działa to dobrze na iPadzie (
UIPopoverController
same prezenty, więc nie wymaga odniesienia do aUIViewController
), uzyskanie tego samego kodu do działania oznacza nagle odwołanie się do twojegopresentViewController
z twojegoUIViewController
. Trochę niespójne, prawda?Jak wspomniano wcześniej, nie jest to najlepsze podejście do posiadania logiki w UIView. Ale nie było sensu pakować kilku wierszy kodu potrzebnych w osobny kontroler.
Tak czy inaczej, oto szybkie rozwiązanie, które dodaje nową właściwość do dowolnego UIView:
źródło
Nie wydaje mi się, aby „złym” pomysłem było ustalenie, kto jest kontrolerem widoku w niektórych przypadkach. Nieodpowiednim pomysłem może być zapisanie odwołania do tego kontrolera, ponieważ może on ulec zmianie, podobnie jak zmiany superviews. W moim przypadku mam moduł pobierający, który przechodzi przez łańcuch odpowiedzi.
//.h
//.m
źródło
Najprostsza pętla do while, aby znaleźć viewController.
źródło
Szybki 4
(bardziej zwięzłe niż inne odpowiedzi)
Mój przypadek użycia, dla których trzeba uzyskać dostęp do widoku pierwszy
UIViewController
: Mam obiekt, który owija się wokółAVPlayer
/AVPlayerViewController
i chcę, aby zapewnić prostąshow(in view: UIView)
metodę, która osadziAVPlayerViewController
sięview
. Do tego muszę dostępuview
„sUIViewController
.źródło
To nie odpowiada bezpośrednio na pytanie, ale raczej zakłada założenie dotyczące pytania.
Jeśli masz widok i w tym widoku musisz wywołać metodę na innym obiekcie, np. Kontrolerze widoku, możesz zamiast tego użyć NSNotificationCenter.
Najpierw utwórz ciąg powiadomień w pliku nagłówkowym
Twoim zdaniem zadzwoń do postNotificationName:
Następnie w kontrolerze widoku dodajesz obserwatora. Robię to w viewDidLoad
Teraz (także w tym samym kontrolerze widoku) zaimplementuj metodę copyString: jak pokazano na @selector powyżej.
Nie twierdzę, że jest to właściwy sposób, aby to zrobić, wydaje się po prostu czystsze niż uruchamianie pierwszego łańcucha odpowiedzi. Użyłem tego kodu, aby zaimplementować UIMenuController na UITableView i przekazać zdarzenie z powrotem do UIViewController, aby móc coś zrobić z danymi.
źródło
To z pewnością zły pomysł i zły projekt, ale jestem pewien, że wszyscy możemy cieszyć się szybkim rozwiązaniem najlepszej odpowiedzi zaproponowanej przez @Phil_M:
Jeśli masz zamiar robić proste rzeczy, takie jak wyświetlanie modalnego okna dialogowego lub danych śledzenia, nie uzasadnia to użycia protokołu. Osobiście przechowuję tę funkcję w obiekcie użytkowym, możesz użyć jej ze wszystkiego, co implementuje protokół UIResponder jako:
Wszystkie podziękowania dla @Phil_M
źródło
Może się tu spóźniam. Ale w tej sytuacji nie lubię kategorii (zanieczyszczenia). Kocham w ten sposób:
źródło
Szybsze rozwiązanie
źródło
sequence
nieco). Więc jeśli „szybki” oznacza „bardziej funkcjonalny”, to myślę, że jest bardziej szybki.Zaktualizowana wersja dla swift 4: Dzięki za @Phil_M i @ paul-slm
źródło
Wersja Swift 4
Przykład użycia
źródło
Dwa rozwiązania od Swift 5.2 :
return
Teraz słowo kluczowe nie jest potrzebne 🤓Rozwiązanie 1:
Rozwiązanie 2:
źródło
Na odpowiedź Phila:
W linii:
id nextResponder = [self nextResponder];
jeśli self (UIView) nie jest widokiem podrzędnym widoku ViewController, jeśli znasz hierarchię self (UIView), możesz również użyć:id nextResponder = [[self superview] nextResponder];
...źródło
Moje rozwiązanie prawdopodobnie byłoby uważane za fałszywe, ale miałem podobną sytuację jak majonez (chciałem przełączać widoki w odpowiedzi na gest w EAGLView) i dostałem w ten sposób kontroler widoku EAGL:
źródło
EAGLViewController *vc = [(EAGLAppDelegate *)[UIApplication sharedApplication].delegate viewController];
.ClassName *object
- gwiazdką.Myślę, że zdarza się, że obserwowany musi poinformować obserwatora.
Widzę podobny problem, w którym UIView w UIViewController reaguje na sytuację i musi najpierw powiedzieć swojemu kontrolerowi widoku nadrzędnego, aby ukrył przycisk Wstecz, a następnie po zakończeniu powiedzieć nadrzędnemu kontrolerowi widoku, że musi wyskoczyć ze stosu.
Próbowałem tego z delegatami bez powodzenia.
Nie rozumiem, dlaczego to zły pomysł?
źródło
Innym łatwym sposobem jest posiadanie własnej klasy widoku i dodanie właściwości kontrolera widoku do klasy widoku. Zwykle kontroler widoku tworzy widok i tam kontroler może ustawić się na właściwość. Zasadniczo jest to zamiast przeszukiwania kontrolera (przy odrobinie włamania), zmuszania kontrolera do ustawienia się na widok - jest to proste, ale ma sens, ponieważ to kontroler „kontroluje” widok.
źródło
Jeśli nie zamierzasz przesłać tego do App Store, możesz również użyć prywatnej metody UIView.
źródło
źródło
Aby uzyskać kontroler danego widoku, można użyć łańcucha UIFirstResponder.
źródło
Jeśli Twoim rootViewController jest UINavigationViewController, który został skonfigurowany w klasie AppDelegate, to
Gdzie c wymagało obejrzenia klasy kontrolerów.
STOSOWANIE:
źródło
Nie ma mowy.
To, co robię, to przekazanie wskaźnika UIViewController do UIView (lub odpowiedniego dziedziczenia). Przepraszam, że nie mogę pomóc w podejściu IB do problemu, ponieważ nie wierzę w IB.
Aby odpowiedzieć na pierwszy komentator: czasami musisz wiedzieć, kto do ciebie zadzwonił, ponieważ określa, co możesz zrobić. Na przykład z bazą danych możesz mieć dostęp tylko do odczytu lub odczyt / zapis ...
źródło