[英]Swift protocol extension
非常感谢有关实例化UIViewController
或UIStoryboard
时使用字符串的文章 。
尽管有一点我想改变行为。 我没有在提供故事板的类方法中使用故事板枚举,而是在这里想要一种符合协议的类型。
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时,却收到编译器错误,抱怨不符合协议!
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
类型。
StringRawRepresentable
与StoryboardRepresentable
不直接相关。
由于协议扩展仅影响同时符合StringRawRepresentable
StoryboardRepresentable
对象,因此必须声明SomeOtherEnum
enum SomeOtherEnum: String, StoryboardRepresentable, StringRawRepresentable {
您可以借助多种协议/扩展来管理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会发生变化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.