あなたはT
にではなく、パラメータviewControllerType
に(場合には、それが存在する)viewControllers.first
をキャストする必要があります。実際には、このパラメータをまったく使用する必要はありません。拡張機能を次のように変更することができます。
extension UINavigationController {
func fhkFindFirst<T: UIViewController>(_: T.Type) -> T? {
for viewController in viewControllers {
if let viewController = viewController as? T {
return viewController
}
}
return nil
}
}
使用例は以下のとおりです。 fooViewController.self
ではなくfooViewController.dynamicType
で電話することに注意してください。後者の場合は、fooViewController.self = fooViewController.self
ではなくの値がfooViewController.self
になります。
ただし、サブクラスタイプからそのスーパークラスへの変換を試みると常に成功するので、上記の解決策ではサブクラスインスタンス(サブクラスはUIViewController
)を正しく識別します。一方、スーパークラスインスタンス(つまり、 T
をスーパークラスUIViewController
とした場合)viewController = viewController as? T
は、viewController
が実際にUIViewController
のサブクラスのインスタンスであっても、常に成功します。
サブクラスのインスタンスを識別するために
fhkFindFirst(...)
を使用し
:OK
次の例では、2つのサブクラスのインスタンスが正しく識別し、その参照は、呼び出し元に返されます。
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> */
スーパークラスのインスタンスを見つけるために、fhkFindFirst(...)
を使用した:
を意図していないとして、次の場合には、fooViewController
はUIViewController
オブジェクトであり、型変換ので、BarViewController
として誤識別されるのに対しBarViewController
オブジェクトの(UINavigationController.viewControllers
)〜UIViewController
が成功しました。
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> */
アップラップします。 UIViewController
のサブクラスを検索するためのメソッドのみを使用する限り、上記は機能します。一方、スーパークラスオブジェクトを検索しようとすると、最初のコントローラはUINavigationController.viewControllers
になります。
edelaney05に関して追加:
edelaney05:コメントを削除するた場合には、私は疑問を引用することから始めましょう
下のコメント欄での関連する質問:これを防ぐ方法はありますか?これは特にあなたが 中級クラスを持っている場合に考慮すべき非常に興味深いケースです。 class FooVC: AwesomeVC { ... }
,class BarVC: AwesomeVC { ... }
、およびclass AwesomeVC: UIViewController { ... }
。
はい、あなたはあなたがUIViewController
のサブクラスのみの純粋な(第一レベル)以外で作業することがあります知っている場合には、この現象を回避することができます。例えば、
- サブクラスから
UIViewController
の最初のインスタンスを見つけることができます。 (+)
- これらのサブクラスのサブクラスです。 (++)
サブクラスインスタンスをそのスーパークラスに変換しないようにするために、動的型比較を使用することができます。したがって、サブクラスインスタンスを私たちが探しているスーパークラスインスタンスとして誤って識別することができますために)。
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!私はそれが何か簡単だと分かっていました。ありがとうございました! .selfと.dynamicTypeを指摘して、将来の頭痛を救ってくれてありがとう。 –
@StephenNewtonお手伝いします。またメソッド名にSwift 'camelCase'命名規則に従うように拡張メソッドを更新しました。 – dfri
@StephenNewton私の編集に注意してください:上のソリューションは、UIViewController'のサブクラスインスタンスのみを検索する限り正常ですが、スーパークラスオブジェクトを検索しようとすると、常に 'UINavigationController.viewControllers'の最初のインスタンスを返します(' UIViewController ')。しかし、すべてのビューコントローラが 'UIViewController'のサブクラスのインスタンスでなければならないので、これはOKです。 – dfri