【问题标题】:Dynamic subclass instantiation in swiftswift中的动态子类实例化
【发布时间】:2018-09-27 07:52:15
【问题描述】:

我是从 Objective-C 来到 Swift 的,Objective-C 可以做很多事情,但 Swift 要复杂得多。比如OOP动态初始化器。

例如我有这段代码在 Objective-C 中工作:

@interface CommonVC: UIViewController
+ (instancetype)showFrom:(UIViewController *)vc;
@end

@implementation CommonVC

+ (instancetype)showFrom:(UIViewController *)vc {
    CommonVC *instance = [self instantiateFrom:vc.nibBundle];
    [vc presentViewController:instance animated:YES completion:nil];
    return instance;
}

// this is like convenience initializer.
+ (instancetype)instantiateFrom:(NSBundle *)aBundle {
    return [self.alloc initWithNibName:NSStringFromClass(self.class) bundle:aBundle];
}

@end

@interface SubClassVC: CommonVC
@end

然后像这样使用子类或超类:

SubClassVC *subVC = [SubClassVC showFrom:self];
// or in swift:
SubClassVC.show(from: self)

但是,在 swift 中,似乎不可能实现这样的东西。我尝试了一些,但总是出现编译错误。这是一个:

class CommonVC: UIViewController {

    class func show(from sender: UIViewController) -> Self {
        let vc = self(sender: sender) // Compiler error: Constructing an object of class type 'Self' with a metatype value must use a 'required' initializer
        sender.present(vc, animated: true, completion: nil)
        return unsafeDowncast(vc, to: self)
    }

    convenience init(sender: UIViewController) {
        self.init(nibName: type(of: self).className, bundle: sender.nibBundle)
        loadView()
    }
}

那么我如何从超类编写 viewController 的通用便利初始化程序,然后用子类调用它?

当然,我的便利 init 有很多东西,我只是简化为这个简单的代码,而且函数 show(from:) 有不同的表示,而不是这个简单的 present(_:animated:completion:)

即使我在初始化后创建一个函数来进行设置,它仍然无法工作

class CommonVC: UIViewController {

    class func show(from sender: UIViewController) -> Self {
        let vc = self.init(nibName: type(of: self).className, bundle: sender.nibBundle) // Compiler error: Constructing an object of class type 'Self' with a metatype value must use a 'required' initializer
        vc.setupAfterInitialize()
        sender.present(vc, animated: true, completion: nil)
        return unsafeDowncast(vc, to: self)
    }

    convenience init(sender: UIViewController) {
        self.init(nibName: type(of: self).className, bundle: sender.nibBundle)
        setupAfterInitialize()
    }

    internal func setupAfterInitialize() {
        // do stuff
        loadView()
    }
}

而且代码看起来很愚蠢,不能方便地初始化convenience

目前,我不能使用类函数show(from:),但将演示文稿移到外面并进行如下操作:

CommonVC.show(from: self)
SubClassVC(sender: self).present()

// instead of this simple presentation:
// SubClassVC.show(from: self)

我什至试过了,但还是不行:

class func show<T: CommonVC>(from sender: UIViewController) -> Self {
    T.init(nibName: type(of: self).className, bundle: sender.nibBundle)
    ....

【问题讨论】:

标签: objective-c swift oop inheritance initialization


【解决方案1】:

当您从 Objective-C 切换到 Swift 时,很容易将您的 Objective-C 风格简单地转换为 Swift 代码。但 Swift 在某些方面有着根本的不同。

也许可以实现一个所有控制器都是其子类的泛型类,但我们倾向于尽可能避免在 Swift 中继承(支持协议和扩展)。

来自 Apple 的一个好的 Swift 经验法则是:“总是从协议开始”...

实际上很容易使用协议和扩展来实现你想要的:

protocol Showable {
    init(className: String, bundle: Bundle?)
    static func show(from: UIViewController) -> Self
}

extension Showable where Self: UIViewController {

    init(className: String, bundle: Bundle?) {
        self.init(nibName: className, bundle: bundle)
    }

    static func show(from: UIViewController) -> Self {
        let nibName = String(describing: self)
        let instance = self.init(className: nibName, bundle: from.nibBundle)
        from.present(instance, animated: true, completion: nil)
        return instance
    }

}

在上面的代码中,我声明了一个Showable 协议和一个提供默认实现的扩展,该默认实现适用于采用类是UIViewController 的实例的情况。

最后,为项目中的每个视图控制器提供此功能,只需声明一个空扩展:

extension UIViewController: Showable { }

通过添加这两个简短的 sn-ps 代码,您现在可以执行您在问题中描述的操作(只要您的视图控制器实例存在适当命名的 nib):

let secondController = SecondViewController.show(from: self)
ThirdController.show(from: secondController)

这就是 Swift 的魅力所在。您所有的UIViewController 子类现在都可以免费获得此功能;不需要继承。

【讨论】:

  • 感谢您的回答,我会尝试您的解决方案并将其标记为已接受。 +1 A good Swift rule of thumb, from Apple, is: "always start with a protocol"
  • 没问题。顺便说一句,如果你从多年的 Objective-C 工作过渡到 Swift,那么我强烈推荐 WWDC 演讲“面向协议的编程”:youtube.com/watch?v=g2LwFZatfTI
猜你喜欢
  • 2020-10-29
  • 2014-01-26
  • 2019-11-08
  • 1970-01-01
  • 1970-01-01
  • 2011-11-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多