【iOS 开发】用泛型简化 instantiateViewController

2017-01-13 15:18:44来源:http://www.jianshu.com/p/7bc4526cab86作者:KyXu人点击

第七城市

使用 storyboard 的时候,我们经常会写出下面这样的代码,用来跳转到其他页面


if let editVC = self.storyboard?.instantiateViewController(withIdentifier: "EditVC") as? EditVC {
self.navigationController?.pushViewController(editVC, animated: true)
}

最多改成这样


guard let editVC = self.storyboard?.instantiateViewController(withIdentifier: "EditVC") as? EditVC else { return }

实在是太冗长了,简化第一步,或许我们可以直接将 EditVC 这个类型字符串化变成 "EditVC",代码变成:


guard let editVC = self.storyboard?.instantiateViewController(withIdentifier: String(describing: EditVC.self)) as? EditVC else { return }

嗯,更长了,但是既然 EditVC 使用了两次,这使得我们有机会把这个过程封装成一个函数,而 EditVC 是唯一需要传递的参数


func instantiateVC(vc:UIViewController) -> UIViewController? {
let id = String(describing: vc.self)
return storyboard?.instantiateViewController(withIdentifier: id)
}
// how to use
guard let editVC = instantiateVC(vc: EditVC()) as? EditVC else { return }

封装之后依然尴尬:


因为我们不能确定每次都需要函数返回 EditVC ,所以只能用 UIViewController 当做返回值,这使得我们还需要再加上 as? EditVC 去做类型转换,相当于还是手动使用了两次 EditVC ,而不是一次
传入的参数是 EditVC() 而不是 EditVC ,看起来丑陋

一次解决两个问题的答案是:泛型!


我们在函数中限定泛型 TUIViewController ,但 T 具体是我们的 App 中的哪个子类我们不去管,通过函数的参数来指定 T 的具体类型,随后确定出我们函数的返回值为那个我们指定的 T


最终结果:


extension UIViewController {
func instantiateVC<T: UIViewController>(type: T.Type) -> T? {
let id = String(describing: T.self)
return storyboard?.instantiateViewController(withIdentifier: id) as? T
}
}
// how to use
guard let editVC = instantiateVC(type: EditVC.self) else { return }

前后对比:


// before
guard let editVC = storyboard?.instantiateViewController(withIdentifier: "EditVC") as? EditVC else { return }
// after
guard let editVC = instantiateVC(type: EditVC.self) else { return }

提醒:
这里我假装这个函数回避掉了直接使用字符串去传入 Storyboard ID 的风险,但可以这么做的前提是,这里的 EditVC"EditVC" 可以直接字符串化。


如果你也要这么做的话,至少要保证你的类名的字符串化的结果和你的 Storyboard ID 是有固定关联的。比如 EditVC 对应 "editvc""EDITVC""editVC" (这样你只要修改字母大小写就可以了),而不是 "abc123" 这种随便写的东西。




第七城市

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台