Swift协议扩展

时间:2016-02-07 19:09:13

标签: ios swift enums protocols

非常感谢article在实例化UIViewControllerUIStoryboard时摆脱使用字符串。

虽然有一点我想改变行为。 我没有在获取故事板的类方法中使用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时,我收到编译错误抱怨非协议一致性?

3 个答案:

答案 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)

StringRawRepresentableStoryboardRepresentable没有直接关系 由于协议扩展仅影响符合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在更改。