Musisz rzucać viewControllers.first
(w przypadku, gdy istnieją) do T
, zamiast parametru viewControllerType
. W rzeczywistości nie będziesz musiał w ogóle korzystać z tego parametru; możesz zmodyfikować swoje rozszerzenie na następujące:
extension UINavigationController {
func fhkFindFirst<T: UIViewController>(_: T.Type) -> T? {
for viewController in viewControllers {
if let viewController = viewController as? T {
return viewController
}
}
return nil
}
}
Przykładowe zastosowanie przedstawiono poniżej. Pamiętaj, że dzwonisz pod numerem fooViewController.dynamicType
zamiast fooViewController.self
. Ta ostatnia podaje wartość o wartości z fooViewController.self
zamiast typu, tj. fooViewController.self = fooViewController.self
.
Należy jednak zauważyć, że próba konwersji z klasy podklasy do jej nadklasy zawsze zakończy się sukcesem, więc powyższe rozwiązanie poprawnie rozpozna instancje podklasy (podklasy UIViewController
), natomiast w przypadku zapytania o wystąpienie nadklasy (np. T
jako nadklasa UIViewController
) wtedy viewController = viewController as? T
zawsze się powiedzie, nawet jeśli viewController
jest w rzeczywistości instancją podklasy UIViewController
.
Korzystanie fhkFindFirst(...)
zidentyfikowanie instancji podklasy: Ok
w poniższym przykładzie dwóch przypadkach podklasy są prawidłowo zidentyfikowane i ich odniesienia powrócił do rozmówcy.
class FooViewController : UIViewController { }
class BarViewController : UIViewController { }
let fooViewController = FooViewController()
let barViewController = BarViewController()
let navController = UINavigationController(rootViewController: fooViewController)
navController.addChildViewController(barViewController)
print(navController.fhkFindFirst(fooViewController.dynamicType) ?? "None found.")
// or: print(navController.fhkFindFirst(FooViewController))
/* <__lldb_expr_1582.FooViewController: 0x7fb97840ad80> */
print(navController.fhkFindFirst(barViewController.dynamicType) ?? "None found.")
// or: print(navController.fhkFindFirst(BarViewController))
/* <__lldb_expr_1582.BarViewController: 0x7fb978709340> */
Korzystanie fhkFindFirst(...)
znaleźć nadklasy instancje: nie zgodnie z przeznaczeniem
Natomiast w następującym przypadku, fooViewController
jest obiektem UIViewController
i jest błędnie zidentyfikowany jako BarViewController
, od typu konwersji z obiektu BarViewController
(w UINavigationController.viewControllers
) na UIViewController
powiodło się.
class BarViewController : UIViewController { }
let fooViewController = UIViewController()
let barViewController = BarViewController()
let navController = UINavigationController(rootViewController: barViewController)
navController.addChildViewController(fooViewController)
print(navController.fhkFindFirst(fooViewController.dynamicType) ?? "None found.")
// or: print(navController.fhkFindFirst(UIViewController))
/* <__lldb_expr_1533.BarViewController: 0x7fa519e2bd40> <-- "wrong" one */
print(navController.fhkFindFirst(barViewController.dynamicType) ?? "None found.")
// or: print(navController.fhkFindFirst(BarViewController))
/* <__lldb_expr_1533.BarViewController: 0x7fa519e2bd40> */
do zawijania; powyższe będzie działać tak długo, jak tylko użyjesz tej metody do wyszukiwania podklas o numerze UIViewController
; natomiast jeśli spróbujesz wyszukać obiekt nadklasy, otrzymasz pierwszy kontroler w UINavigationController.viewControllers
.
Dodawanie w zakresie edelaney05: s powiązane pytanie w komentarzach poniżej
zacznę cytując pytanie w przypadku komentarza miały zostać usunięte:
edelaney05 : Czy istnieje sposób, aby się przed tym uchronić? Jest to bardzo ciekawy przypadek, który należy wziąć pod uwagę, szczególnie jeśli masz klasę pośrednią . class FooVC: AwesomeVC { ... }
, class BarVC: AwesomeVC { ... }
i class AwesomeVC: UIViewController { ... }
.
Tak, można obejść ten problem, w przypadku znasz będziesz pracował z innymi niż tylko czystego (1 poziomie) podklasy UIViewController
; powiedzmy, aby umożliwić znalezienie pierwszego wystąpienia podrzędnego:
- Podklasy do
UIViewController
. (+)
- Podklasy do tych podklas. (++)
Możemy skorzystać z dynamicznego porównywania typów, aby upewnić się, że nie wykonujemy konwersji instancji podklasy do jej nadklasy (i dlatego błędnie identyfikujemy instancję podklasy jako instancję nadklasy, której szukamy dla).
extension UINavigationController {
func fhkFindFirst<T: UIViewController>(_: T.Type) -> T? {
for viewController in viewControllers {
if let supClassType = viewController.superclass?.dynamicType where supClassType != T.Type.self {
if let viewController = viewController as? T {
return viewController
}
}
}
return nil
}
}
class FooBarViewController: UIViewController { }
class FooViewController : FooBarViewController { }
class BarViewController : FooBarViewController { }
let fooBarViewController = FooBarViewController()
let fooViewController = FooViewController()
let barViewController = BarViewController()
let navController = UINavigationController(rootViewController: fooViewController)
navController.addChildViewController(barViewController)
navController.addChildViewController(fooBarViewController)
print(navController.fhkFindFirst(FooViewController) ?? "None found.")
/* <__lldb_expr_1582.FooViewController: 0x7fe22a712e40> */
print(navController.fhkFindFirst(BarViewController) ?? "None found.")
/* <__lldb_expr_1582.BarViewController: 0x7fe22a4196a0> */
print(navController.fhkFindFirst(FooBarViewController) ?? "None found.")
/* <__lldb_expr_1582.FooBarViewController: 0x7fe22a70ee60> */
Ah! Wiedziałem, że to będzie coś prostego. Dziękuję Ci! I dzięki za uratowanie mi przyszłego bólu głowy przez wskazanie .self vs .dynamicType. –
@StephenNewton Z przyjemnością pomożemy. Zwróć też uwagę, że zaktualizowałem metodę rozszerzenia, aby zastosować konwencję nazewnictwa Swift 'camelCase' dla nazw metod. – dfri
@StephenNewton Notatka moja edycja: powyższe rozwiązanie działa dobrze, dopóki wyszukiwane są instancje podklasy 'UIViewController', ale zawsze zwraca pierwszą instancję w' UINavigationController.viewControllers', jeśli spróbujesz wyszukać obiekt nadklasy ('UIViewController '). To powinno być jednak w porządku, ponieważ wszystkie kontrolery viewinner powinny być instancjami podklas obiektu 'UIViewController'. – dfri