繁体   English   中英

Swift协议扩展

[英]Swift protocol extension

非常感谢有关实例化UIViewControllerUIStoryboard时使用字符串的文章

尽管有一点我想改变行为。 我没有在提供故事板的类方法中使用故事板枚举,而是在这里想要一种符合协议的类型。

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类型。

StringRawRepresentableStoryboardRepresentable不直接相关。
由于协议扩展仅影响同时符合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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM