所有符合协议的类继承默认实现 [英] All Classes Conforming to Protocol Inherit Default Implementation

查看:74
本文介绍了所有符合协议的类继承默认实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我为所有 UIViewController 子类添加了一个方法,允许我从类和它在里面的故事板实例化它.

I've added a method to all my UIViewController subclasses that allows me to instantiate it from the class and the storyboard it's inside.

所有方法都遵循以下格式:

All the methods follow this format:

class func instantiateFromStoryboard() -> CameraViewController? {

    let storyboard = UIStoryboard(name: "Camera", bundle: nil)

    let initial = storyboard.instantiateInitialViewController()

    guard let controller = initial as? CameraViewController else {
        return nil
    }

    return controller
}

相反,我想创建一个协议,Instantiatable,它需要上述方法和一个变量,storyboardName: String.

Instead, I would like to make a protocol, Instantiatable, that requires the above method along with a variable, storyboardName: String.

然后,我想扩展这个 Instantiatable 使其包含与上述类似的实现.我的目标是我可以声明一个 UIViewController 遵守这个协议,我需要定义的只是 storyboardName.

Then, I'd like to extend this Instantiatable so it contains a similar implementation as above. My objective is that I can state that a UIViewController adheres to this protocol, and all that I have to define is the storyboardName.

我觉得我已经接近这个实现了:

I feel like I'm close with this implementation:

protocol Instantiatable {
    var storyboardName: String { get }
    func instantiateFromStoryboard() -> Self?
}

extension Instantiatable where Self: UIViewController {
    func instantiateFromStoryboard() -> Self? {

        let storyboard = UIStoryboard(name: storyboardName, bundle: nil)

        let initial = storyboard.instantiateInitialViewController()

        guard let controller = initial as? Self else {
            return nil
        }

        return controller
    }
}

但是,当我尝试向 CameraViewController 添加一致性时,出现错误:

However, when I try to add conformance to CameraViewController, I get the error:

方法 instantiateFromStoryboard() 在非 final 类 CameraViewController 必须返回 Self 以符合协议 Instantiatable

Method instantiateFromStoryboard() in non-final class CameraViewController must return Self to conform to protocol Instantiatable

我错过了什么?

谢谢.

推荐答案

您可以使用泛型来实现您的目标.像这样:

You can use generics to achieve what you are after. Something like this:

protocol Instantiatable {
    static func instantiateFromStoryboard<T: UIViewController>() -> T?
}

extension Instantiatable where Self: UIViewController {
    static func instantiateFromStoryboard<T: UIViewController>() -> T? {

        let storyboard = UIStoryboard(name: self.description(), bundle: nil)

        let initial = storyboard.instantiateInitialViewController() as? T

        guard let _ = initial as? Self else {
            return nil
        }     
        return initial
    }
}

所以,如果 VCA 是 instantiatable 你可以说 let vCA = VCA.InstantiateFromStoryboard()

So, if VCA is instantiatable you can say let vCA = VCA.InstantiateFromStoryboard()

我将函数更改为类函数,以便您可以在类上调用它,而不需要视图控制器的实例.这段代码使用类名来检索storyboard文件,但这意味着你的storyboard需要被称为projectname.classname.storyboard,有点难看.

I changed the function to be a class function, so that you can call it on the class, rather than needing an instance of the view controller. This code uses the class name to retrieve the storyboard file, but this means that your storyboard needs to be called projectname.classname.storyboard, which is a bit ugly.

另一种方法是要求您的视图控制器类实现一个返回故事板名称的函数:

Another approach is to require your view controller classes to implement a function that returns the name of the storyboard:

protocol Instantiatable {
  //  var storyboardName: String { get }
    static func instantiateFromStoryboard<T: UIViewController>() -> T?
    static func storyboardName() -> String
}

extension Instantiatable where Self: UIViewController {
    static func instantiateFromStoryboard<T: UIViewController>() -> T? {

        let storyboard = UIStoryboard(name: self.storyboardName(), bundle: nil)           
        let initial = storyboard.instantiateInitialViewController() as? T

        guard let _ = initial as? Self else {
            return nil
        }            
        return initial
    }
}

然后在每个 Instantiatable 中你需要实现:

Then in each Instantiatable you would need to implement:

static func storyboardName() -> String {
    return "ViewController" // (or whatever the storyboard name is)
}

编辑

第三个(可能也是最好的)替代方法是根据您的回答和@AliSoftware 的评论,让您的 UIViewController 子类成为 final 子类.

The third (and probably best) alternative is to make your UIViewController subclasses final, as per your answer and @AliSoftware's comments.

这让你可以使用

protocol Instantiatable {
  //  var storyboardName: String { get }
    static func instantiateFromStoryboard() -> Self?
    static func storyboardName() -> String
}

extension Instantiatable where Self: UIViewController {
    static func instantiateFromStoryboard() -> Self? {

        let storyboard = UIStoryboard(name: self.storyboardName(), bundle: nil)

        let initial = storyboard.instantiateInitialViewController() as? Self

        return initial
    }
}

只要你声明你的视图控制器是:

as long as you declare your view controllers to be:

final class ViewController: UIViewController, Instantiatable {
  ....

这篇关于所有符合协议的类继承默认实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆