SwiftはperformSegueWithIdentifierまたはストーリーボードを備えた便利なルーターを改善します

iOSまたはOS Xのまれな開発者はストーリーボードを使用せず、画面間でデータを転送しなかったプログラマーはさらに少なかった。

私たちはすべて、performSegueWithIdentifierメソッドとそれを使用することの難しさを知っています。



ある瞬間にSwiftでプロジェクトを開始したとき、「強く型付けされた言語でデータ転送にラッパーを使用する必要があるのはなぜですか?」

数分後、ソリューションのビジョンが形成され、すぐに実装されました。



素材が非常に小さいので、それについて書く価値があるかどうか長い間考えていましたが、これらの50行は非常に役立ちます



menuController?.performSegueWithIdentifier(changeItemIdentifier, sender: nil) { segue in let controller = segue.destinationViewController as! ChangeMenuItemController controller.viewModel.sourceMenuItem = item }
      
      







したがって、ストーリーボードとルーターを一緒に使用するのは簡単です。 prepareForSegueの過剰な成長を排除し、コードを読み取るためのコンテキストを増やします。 同時に、便利な状況でprepareForSegueを放棄することを強制しません。



仕組みを見てみましょう 私はユニークなふりをしていませんが、興味深いアプローチのようです。





1)performSegueWithIdentifierに似たメソッドを作成しますが、パラメータークロージャーを追加します(構成)

2)設定を保存

3)performSegueWithIdentifierメソッドを呼び出します

4)prepareForSegueの呼び出し時に、configurateを呼び出すだけです。



クラスを書くことはできますが、カテゴリを書く方がはるかに生産的です。

微妙な点は、configurateを保存し、prepareForSegueから呼び出すことです(これはアクションで中断しないことが重要です)。

保存するには、連想リンクを使用します。 prepareForSegueの代わりに、メソッドが呼び出され、そこからconfigurateが呼び出され、それから元のメソッドが呼び出されます。



トップレベルコード
 typealias ConfiguratePerformSegue = (UIStoryboardSegue) -> () func performSegueWithIdentifier(identifier: String, sender: AnyObject?, configurate: ConfiguratePerformSegue?) { swizzlingPrepareForSegue() configuratePerformSegue = configurate performSegueWithIdentifier(identifier, sender: sender) }
      
      









実装は非常に小さく、スポイラーの下にコードを添付する方が簡単です

実装
 class Box { let value: Any init(_ value: Any) { self.value = value } } extension UIViewController { struct AssociatedKey { static var ClosurePrepareForSegueKey = "ClosurePrepareForSegueKey" static var token: dispatch_once_t = 0 } typealias ConfiguratePerformSegue = (UIStoryboardSegue) -> () func performSegueWithIdentifier(identifier: String, sender: AnyObject?, configurate: ConfiguratePerformSegue?) { swizzlingPrepareForSegue() configuratePerformSegue = configurate performSegueWithIdentifier(identifier, sender: sender) } private func swizzlingPrepareForSegue() { dispatch_once(&AssociatedKey.token) { let originalSelector = #selector(UIViewController.prepareForSegue(_:sender:)) let swizzledSelector = #selector(UIViewController.closurePrepareForSegue(_:sender:)) let instanceClass = UIViewController.self let originalMethod = class_getInstanceMethod(instanceClass, originalSelector) let swizzledMethod = class_getInstanceMethod(instanceClass, swizzledSelector) let didAddMethod = class_addMethod(instanceClass, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)) if didAddMethod { class_replaceMethod(instanceClass, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)) } else { method_exchangeImplementations(originalMethod, swizzledMethod) } } } func closurePrepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { configuratePerformSegue?(segue) closurePrepareForSegue(segue, sender: sender) configuratePerformSegue = nil } var configuratePerformSegue: ConfiguratePerformSegue? { get { let box = objc_getAssociatedObject(self, &AssociatedKey.ClosurePrepareForSegueKey) as? Box return box?.value as? ConfiguratePerformSegue } set { objc_setAssociatedObject(self, &AssociatedKey.ClosurePrepareForSegueKey, Box(newValue), objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) } } }
      
      









以上です。 これは、objcとSwiftの両方で機能する非常に小さなハックです。

これは、以前に記述したコードに違反しないだけでなく、両方のアプローチを組み合わせたり、ブロックから構成に完全に切り替えたりすることもできます。

また、特別なルータークラスの画面間の遷移を依存させて、ストーリーボードとともに使用することもできます。



upd:通信後、ポッドの形で投稿し、自動キャスト UIViewControllerで使用します。

cocoapods.org/pods/PureSegue



All Articles