当你用 UIStoryBoard (以下简称 'SB') 做iOS开发时候,总是避免不了设置 StoryBoard ID
的问题, StoryBoard ID
是一个字符串,这种硬编码的形式如果时间久远,就很容易忘记, 也容易导致拼写的错误。 我们常常使用最简单的复制、粘贴的形式来保证一致,但是偶尔也会出现那种失误性的新增或者删除。而当 SB 大到一定的规模,打开 SB 查找对应的 StoryBoard ID
的卡顿也是难以忍受的。
我希望在我运行的时候,编辑器能帮忙检查此类,尽可能减少错误的信息。类似这种:
UIStoryboard.main.instantiateViewController(withIdentifier: .SecondViewController)复制代码
以下是我的实现详情:
1. StoryboardInitializable
StoryboardInitializable
是初始化 StoryBoard 所必须的,它需要一个 name
以及 bundle
. 大多时候 bundle
默认为 nil
protocol StoryboardInitializable { static var name: String { get } static var bundle: Bundle? { get }}extension StoryboardInitializable { static var bundle: Bundle? { return nil }}复制代码
2. IDConvertible
当实例化一个控制器的时候,就需要使用到对应的 StoryBoard ID
,我们需要让编辑器知道检查对应的类型。
protocol IDConvertible { associatedtype IDIdentity}复制代码
3. ControllerInitializable
这里是实例化控制器的协议,提供了系统默认的两个方法以及自定义的一个,提供类似原生的使用效果。
protocol ControllerInitializable: StoryboardInitializable, IDConvertible { func instantiateInitialViewController() -> UIViewController? func instantiateViewController(withIdentifier identifier: Self.IDIdentity) -> UIViewController func instantiateViewController(withIdentifier identifier: String) -> UIViewController}extension ControllerInitializable { func instantiateInitialViewController() -> UIViewController? { return UIStoryboard(name: Self.name, bundle: Self.bundle).instantiateInitialViewController() }}extension ControllerInitializable where IDIdentity: RawRepresentable, IDIdentity.RawValue == String { func instantiateViewController(withIdentifier identifier: Self.IDIdentity) -> UIViewController { return instantiateViewController(withIdentifier: identifier.rawValue) } func instantiateViewController(withIdentifier identifier: String) -> UIViewController { return UIStoryboard(name: Self.name, bundle: Self.bundle).instantiateViewController(withIdentifier: identifier) } }extension ControllerInitializable where IDIdentity == String { func instantiateViewController(withIdentifier identifier: Self.IDIdentity) -> UIViewController { return UIStoryboard(name: Self.name, bundle: Self.bundle).instantiateViewController(withIdentifier: identifier) }}复制代码
4. StringConvertible
从 SB 中实例化 UIViewController 需要提供对应的 StoryBoardID, 此处提供一个 转换为 String 的协议。
protocol StringConvertible { var string: String { get }}extension ControllerInitializable where IDIdentity: StringConvertible { func instantiateViewController(withIdentifier identifier: Self.IDIdentity) -> UIViewController { return instantiateViewController(withIdentifier: identifier.string) } func instantiateViewController(withIdentifier identifier: String) -> UIViewController { return UIStoryboard(name: Self.identifier, bundle: Self.bundle).instantiateViewController(withIdentifier: identifier) }}复制代码
给 UIStoryboard 做对应的扩展
extension UIStoryboard { static var main: UIStoryboard.Main { return Main() } public struct Main: ControllerInitializable { typealias IDIdentity = EnumIdentifier static var name: String { return "Main"} public enum EnumIdentifier: String { case SecondViewController case OtherViewController } }}复制代码
使用方法:
UIStoryboard.main.instantiateViewController(withIdentifier: .SecondViewController)复制代码