非常感谢article在实例化UIViewController
或UIStoryboard
时摆脱使用字符串。
虽然有一点我想改变行为。 我没有在获取故事板的类方法中使用Storyboard枚举,而是希望这里的类型符合协议。
extension UIStoryboard {
class func storyboard(storyboard: StoryboardRepresentable, bundle: NSBundle? = nil) -> UIStoryboard {
return UIStoryboard(name: storyboard.storyboardName, bundle: bundle)
}
}
protocol StringRawRepresentable: RawRepresentable {
typealias RawValue = String
var rawValue: String { get }
}
protocol StoryboardRepresentable {
var storyboardName: String { get }
}
extension StoryboardRepresentable where Self: StringRawRepresentable {
var storyboardName: String {
return self.rawValue
}
}
enum SomeOtherEnum: String, StoryboardRepresentable {
case BlaMain
case BlaSub
case BlaSomeThing
var storyboardName: String { return self.rawValue }
}
有了这个(假设你有几个使用这个实现很有趣的模块),模型本身可以有符合StoryboardRepresentable的新枚举类型,而不是拥有关于所有使用的故事板的知识的集中枚举,从而创建依赖。
这是我的问题。虽然我已在扩展中实现了storyboardName,但是当我删除SomeOtherEnum上的storyboardName时,我收到编译错误抱怨非协议一致性?
答案 0 :(得分:2)
extension UIStoryboard {
class func storyboard(storyboard: StoryboardRepresentable, bundle: NSBundle? = nil) -> UIStoryboard {
return UIStoryboard(name: storyboard.storyboardName, bundle: bundle)
}
}
protocol StoryboardRepresentable {
var storyboardName: String { get }
}
extension StoryboardRepresentable where Self: RawRepresentable, Self.RawValue == String {
var storyboardName: String {
return self.rawValue
}
}
enum SomeOtherEnum: String, StoryboardRepresentable {
case BlaMain
case BlaSub
case BlaSomeThing
}
StoryboardRepresentable
现在可以应用于String
类型的任何枚举,但不能应用Int
。
答案 1 :(得分:0)
StringRawRepresentable
与StoryboardRepresentable
没有直接关系
由于协议扩展仅影响符合StoryboardRepresentable
的{{1}}个对象,因此您必须声明StringRawRepresentable
SomeOtherEnum
答案 2 :(得分:0)
您可以借助多种协议/扩展来管理Storyboard和ViewController实例化。
UIStoryboardInstantiatable是通用实例化方法的包装:
public protocol UIStoryboardInstantiatable {
func instantiate<T: UIViewController>(controller: T.Type) -> T?
func instantiateInitial<T: UIViewController>(controller: T.Type) -> T?
func instantiateInitial() -> UIViewController?
}
public extension UIStoryboardInstantiatable {
func instantiateInitial() -> UIViewController? {
return instantiateInitial(controller: UIViewController.self)
}
}
public extension UIStoryboardInstantiatable where Self: UIStoryboardRepresentable {
func instantiate<T: UIViewController>(controller: T.Type) -> T? {
return storyboard.instantiate(controller: T.self)
}
func instantiateInitial<T: UIViewController>(controller: T.Type) -> T? {
return storyboard.instantiateInitial(controller: T.self)
}
}
public extension UIStoryboardInstantiatable where Self: UIStoryboard {
func instantiate<T: UIViewController>(controller: T.Type) -> T? {
return instantiateViewController(withIdentifier: T.className) as? T
}
func instantiateInitial<T: UIViewController>(controller: T.Type) -> T? {
return instantiateInitialViewController() as? T
}
}
将来,我们所有的故事板都将是UIStoryboardRepresentables。
public protocol UIStoryboardRepresentable: UIStoryboardInstantiatable {
var storyboard: UIStoryboard { get }
var bundle: Bundle { get }
}
public extension UIStoryboardRepresentable where Self: RawRepresentable, Self.RawValue == String {
var storyboard: UIStoryboard {
return UIStoryboard.init(name: rawValue, bundle: bundle)
}
}
现在,您可以创建应用程序中显示的情节提要列表:
public enum AppStoryboard: String, UIStoryboardRepresentable {
case components
case main
case news
public var bundle: Bundle {
return Bundle.main
}
public var rawValue: String {
return "\(self)".capitalizingFirstLetter()
}
}
小字符串扩展名,用于将rawValue的首字母大写。因为按照惯例,情节提要板的名称是pascal大小写,枚举类型是驼峰式大小写。
extension String {
public func capitalizingFirstLetter() -> String {
return prefix(1).uppercased() + dropFirst()
}
}
用法:
let controller = AppStoryboard.main.instantiate(controller: TestViewController.self)
从一个项目到另一个项目,仅AppStoryboard在更改。