美文网首页
Swift 从 UIStoryboard 加载 UIViewCo

Swift 从 UIStoryboard 加载 UIViewCo

作者: fd5657ed541e | 来源:发表于2017-06-18 17:42 被阅读1706次

    结合Swift的 protocol & Generic 对UITableIView和UICollectionView的复用可以GIt搜索Reusable
    从UIStoryboard加载UIViewController类似
    首先要保证UIViewController的storyboardID 和 类名相同

    image.png

    Talk is cheap, show me the code...

    /// 获取类名
    protocol Identifiable {
        static var identifier: String { get }
    }
    
    /// 自己默认实现 返回类名
    extension Identifiable {
        static var identifier: String { return "\(self)" }
    }
    
    /// UIViewController 类型免费获得了 identifier 属性
    extension UIViewController: Identifiable {}
    
    /// 核心协议
    protocol StoryboardLoader {
        
        /// 占位符, 要加载的 UIViewController 类型
        associatedtype ViewController: UIViewController
    
        /// 要加载的 UIViewController 实例
        var value: ViewController { get }
    }
    
    /// 默认实现
    /// RawRepresentable , Self.RawValue == String 这个对应storyboard名字, 如 main.sb, order.sb
    extension StoryboardLoader where Self: RawRepresentable, Self.RawValue == String {
        
        var value: ViewController {
            
            if let vc = UIStoryboard(name: rawValue, bundle: nil)
                .instantiateViewController(withIdentifier: ViewController.identifier)
                as? ViewController {
                return vc
            }
            fatalError("cannot load viewController with storyboard name: \(rawValue), identifier: \(ViewController.identifier)")
        }
    }
    
    

    根据协议的约束很容易就想到 enum最容易实现这个类型,于是有:

    enum Storyboard<T: UIViewController>: String, StoryboardLoader {
        /// 占位符类型
        typealias ViewController = T
        case one = "One"
        case another = "Another"
    }
    

    或者:

    /// ExpressibleByStringLiteral: String 的字面量协议 方便初始化, 更加直观
    /// 例如 let sb: Storyboard = "One"
    struct Storyboard<T: UIViewController>: RawRepresentable, StoryboardLoader, ExpressibleByStringLiteral {
        
        static var one: StoryboardStruct<T> { return "One" }
        static var another: StoryboardStruct<T> { return "Another" }
        
        typealias ViewController = T
        
        let rawValue: String
        
        init?(rawValue: String) {
            self.rawValue = rawValue
        }
        
        init(stringLiteral value: String) {
            rawValue = value
        }
        
        init(unicodeScalarLiteral value: String) {
            rawValue = value
        }
        
        init(extendedGraphemeClusterLiteral value: String) {
            rawValue = value
        }
    }
    

    然后调用:

    /// 获取 another.soryboard 里的 AnotherViewController实例
    let anotherViewController = Storyboard<AnotherViewController>.another.value
    /// 获取 another.soryboard 里的 AnotherTableViewController实例
    let anotherTableViewController = Storyboard<AnotherTableViewController>.another.value
    

    Demo 连接
    https://github.com/287258813/StoryboardLoader

    相关文章

      网友评论

          本文标题:Swift 从 UIStoryboard 加载 UIViewCo

          本文链接:https://www.haomeiwen.com/subject/aatwqxtx.html