Prąd UIViewController
na ekranie musi odpowiadać na powiadomienia push z APN, ustawiając niektóre widoki znaczków. Ale jak mogę uzyskać UIViewController
metodę in application:didReceiveRemoteNotification
: of AppDelegate.m
?
Próbowałem użyć, self.window.rootViewController
aby uzyskać bieżące wyświetlanie UIViewController
, może to być UINavigationViewController
kontroler widoku lub inny rodzaj. I dowiaduję się, że visibleViewController
właściwość UINavigationViewController
można wykorzystać, aby uzyskać UIViewController
obraz na ekranie. Ale co mogę zrobić, jeśli to nie jest UINavigationViewController
?
Każda pomoc jest mile widziana! Powiązany kod jest następujący.
AppDelegate.m
...
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
//I would like to find out which view controller is on the screen here.
UIViewController *vc = [(UINavigationViewController *)self.window.rootViewController visibleViewController];
[vc performSelector:@selector(handleThePushNotification:) withObject:userInfo];
}
...
ViewControllerA.m
- (void)handleThePushNotification:(NSDictionary *)userInfo{
//set some badge view here
}
źródło
UIView
instancji.rootViewController
to nie koniecznie aktualnie pokazany sterownik. Znajduje się na samym szczycie hierarchii widoków.Zawsze uwielbiam rozwiązania obejmujące kategorie, ponieważ są one przykręcone i można je łatwo wykorzystać ponownie.
Więc stworzyłem kategorię w UIWindow. Możesz teraz wywołać visibleViewController w UIWindow, a to zapewni ci widoczny kontroler widoku, przeszukując hierarchię kontrolerów. Działa to, jeśli używasz nawigacji i / lub kontrolera paska kart. Jeśli chcesz zasugerować inny typ kontrolera, daj mi znać, a mogę go dodać.
UIWindow + PazLabs.h (plik nagłówkowy)
UIWindow + PazLabs.m (plik implementacyjny)
Szybka wersja
źródło
Proste rozszerzenie dla UIApplication w Swift (dba nawet o więcej NavigationController w
UITabBarController
iPhone) :Proste użycie:
Działa idealnie :-)
UPDATE dla czystego kodu:
źródło
Możesz również wysłać powiadomienie za pośrednictwem NSNotificationCenter. Pozwala to poradzić sobie z wieloma sytuacjami, w których przechodzenie przez hierarchię kontrolera widoku może być trudne - na przykład podczas prezentowania modali itp.
Na przykład,
W każdym z kontrolerów widoku:
Można również zastosować to podejście do elementów sterujących przyrządu, które wymagają aktualizacji po odebraniu powiadomienia i są używane przez kilka kontrolerów widoku. W takim przypadku obsłuż wywołania obserwatora add / remove w metodach init i dealloc, odpowiednio.
źródło
addObserver:bar
środkuviewDidLoad
? Czy muszę zastąpićself
?Kod
Oto podejście wykorzystujące świetną składnię przełączników w języku Swift 3/4/5 :
Podstawowy pomysł jest taki sam jak w odpowiedzi zirinisp, po prostu używa składni bardziej podobnej do języka Swift 3+.
Stosowanie
Prawdopodobnie chcesz utworzyć plik o nazwie
UIWindowExtension.swift
. Upewnij się, że zawieraimport UIKit
instrukcję, teraz skopiuj powyższy kod rozszerzenia .Po stronie wywołania może być używany bez określonego kontrolera widoku :
Lub jeśli wiesz, że kontroler widocznego widoku jest dostępny z określonego kontrolera widoku :
Mam nadzieję, że to pomoże!
źródło
presentingViewController
i przekazaniepresentingViewController.presentedViewController
jako parametru do metody rekurencyjnej.UIWindow.visibleViewController(from: presentedViewController)
zamiast tegoUIWindow.visibleViewController(from: presentingViewController.presentedViewController)
?presentedViewController
iviewController
jest tym samym obiektem i będzie wywoływać metodę ze sobą, dopóki stos się nie przepełni (gra słów zamierzona). Tak będziecase let presentingViewController where viewController?.presentedViewController != nil: return UIWindow.visibleViewController(from: presentingViewController.presentedViewController)
Odkryłem, że iOS 8 wszystko schrzanił. W iOS 7 pojawia się nowa
UITransitionView
hierarchia widoków, ilekroć masz prezentację modalnąUINavigationController
. W każdym razie, oto mój kod, który wyszukuje najwyższy VC. PołączeniegetTopMostViewController
powinno zwrócić VC, który powinieneś być w stanie wysłać wiadomość, taką jakpresentViewController:animated:completion
. Jego celem jest uzyskanie VC, którego możesz użyć do zaprezentowania modalnego VC, więc najprawdopodobniej zatrzyma się i wróci do klas kontenerów, takich jak,UINavigationController
a NIE VC w nich zawartego. Dostosowanie kodu również do tego nie powinno być trudne. Przetestowałem ten kod w różnych sytuacjach w iOS 6, 7 i 8. Daj mi znać, jeśli znajdziesz błędy.źródło
O wiele mniej kodu niż wszystkie inne rozwiązania:
Wersja Objective-C:
Wersja Swift 2.0: (autorstwo dla Steve.B)
Działa w dowolnym miejscu aplikacji, nawet z modami.
źródło
UINavigationController
który ma własne elementy podrzędne.Odpowiedź zirinisp w Swift:
Stosowanie:
źródło
as!
inavigationController.visibleViewController!
dla Swift 2.0Określ tytuł dla każdego ViewController, a następnie uzyskaj tytuł bieżącego ViewController za pomocą kodu podanego poniżej.
Następnie sprawdź to po tytule w ten sposób
źródło
self.title = myPhotoView
Mój jest lepszy! :)
źródło
Dlaczego nie obsłużyć po prostu kodu powiadomienia wypychanego w delegacie aplikacji? Czy jest to bezpośrednio związane z widokiem?
Możesz sprawdzić, czy widok UIViewControllera jest obecnie widoczny, sprawdzając, czy jego
window
właściwość widoku ma wartość. Zobacz więcej tutaj .źródło
Tylko dodatek do odpowiedzi @zirinisp.
Utwórz plik, nazwij go
UIWindowExtension.swift
i wklej następujący fragment:Używaj go wszędzie jako:
Dzięki @zirinisp.
źródło
Odnośnie postu NSNotificationCenter powyżej (przepraszam, nie mogę dowiedzieć się, gdzie zamieścić komentarz pod nim ...)
Na wypadek, gdyby niektórzy otrzymywali pewnego rodzaju błąd - [NSConcreteNotification allKeys]. Zmień to:
do tego:
źródło
To zadziałało dla mnie. Mam wiele celów, które mają różne kontrolery, więc poprzednie odpowiedzi wydawały się nie działać.
najpierw chcesz to w swojej klasie AppDelegate:
następnie w swojej funkcji
źródło
To najlepszy możliwy sposób, jaki wypróbowałem. Gdyby to komukolwiek pomogło ...
źródło
Dzięki temu możesz łatwo uzyskać kontroler widoku z góry w taki sposób
Należy zauważyć, że jeśli obecnie wyświetlany jest kontroler UIAlertController,
UIApplication.topMostViewController
zwróci plikUIAlertController
.źródło
Odpowiedź dżungliediewa w wersji Swift 2.0
źródło
Utworzyłem kategorię dla
UIApplication
zvisibleViewControllers
własnością. Główny pomysł jest dość prosty. I swizzledviewDidAppear
iviewDidDisappear
metodyUIViewController
. WviewDidAppear
metodzie viewController jest dodawany do stosu. WviewDidDisappear
metodzie viewController jest usuwany ze stosu.NSPointerArray
jest używany zamiastNSArray
do przechowywaniaUIViewController
odniesień do słabych . To podejście działa dla dowolnej hierarchii ViewControllers.UIApplication + VisibleViewControllers.h
UIApplication + VisibleViewControllers.m
https://gist.github.com/medvedzzz/e6287b99011f2437ac0beb5a72a897f0
Wersja Swift 3
UIApplication + VisibleViewControllers.swift
https://gist.github.com/medvedzzz/ee6f4071639d987793977dba04e11399
źródło
Zawsze sprawdzaj konfigurację kompilacji, jeśli używasz aplikacji z debugowaniem lub wydaniem.
WAŻNA UWAGA: nie możesz go przetestować bez uruchamiania aplikacji w trybie debugowania
To było moje rozwiązanie
źródło