概要
ProtocolExtension
の学習がでらに画面遷移時にパラメータを渡すような処理を実装してみたサンプルです。
アイデア自体はObjCで上司が書いた画面遷移カテゴリを参考にしています。
ProtocolExtensionについて
プロトコルに基底の処理を実装できるSwiftの機能です。APIKitなどのライブラリで型制約したリクエストをつくる際に利用方法されていたりします。
まずはProtocolの実装
ViewControllerから呼び出して遷移するためのメソッド showViewController
は<T:RoutingProtocol>
を追加してRoutingProtocol
に準拠したViewControllerと、コメントで頂きましたParam型のパラメータしか利用できないよう制約をつけています。
setupWithParams
はパラメータを受け取るためのメソッドです。
protocol RoutingProtocol{
typealias Param = AnyObject
/**
pushViewcontroller with any argument
- parameter viewController: conform to RoutingProtocol
- parameter params: any argument
*/
func showViewController<T:RoutingProtocol>(viewController:T, params:T.Param?)
/**
By overridden by viewController conforming to RoutingProtocol,
and receives parameters from the transition source
- parameter params: any arugument
*/
func setupWithParams(params:Param?)
}
つづいてProtocolExtension
基底の処理を実装します。
extension RoutingProtocol where Self: UIViewController{
func setupWithParams(params:Param?) {}
func showViewController<T:RoutingProtocol>(viewController:T, params:T.Param?){
viewController.setupWithParams(params)
guard let vc = viewController as? UIViewController else{
print("cast failure")
return
}
self.navigationController?.pushViewController(vc, animated: true)
}
}
ポイント1
setupWithParamsはプロトコルに準拠したViewControllerがオーバーライドしたときのみパラメータを受け取れるように中身を空で実装しています。引数を受け取る必要のないViewController等は実装の手間が省けます。
ポイント2
func showViewController<T:RoutingProtocol>(viewController:T, params:Param?)
で型制約を行うことでRoutingProtocol
に準拠したViewControllerと引数を受け取ってsetupWithParams
メソッドを呼び出し、パラメータを渡すことができます。
今回は実装してませんがnavigationControllerを持っている前提の遷移処理になっていますので無い場合は追加するなり、モーダルにするなりの対応が必要ですかね。
利用方法
遷移元は勿論、遷移先であるDetailViewController()もRoutingProtocolに準拠していることがshowViewController
メソッド呼び出し時に求められます。渡すパラメータは DetailViewControllerで指定しているStringでないと怒られます。
class ViewController: UIViewController, RoutingProtocol {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func showDetailDidTap(sender: UIButton) {
self.showViewController(DetailViewController(), params:"anything")
}
}
遷移先
Param型の指定を行うことで setupWithParams
で受け取りたいパラメータの型制約をしています。
class DetailViewController: UIViewController, RoutingProtocol{
// parameter type Constraints
typealias Param = String
// MARK: override
func setupWithParams(params: Param?) {
print("\(params!)")
}
}