快速的动态子类实例化

时间:2018-09-27 07:52:15

标签: objective-c swift oop inheritance initialization

我是从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)

但是,迅速实现这样的事情似乎是不可能的。我尝试了一些,但是总是出现编译错误。这是一个:

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的通用便利初始化程序,然后使用子类进行调用呢?

当然,我的便便性初始化有很多东西,我只是简化为这个简单的代码,而且功能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)
    ....

1 个答案:

答案 0 :(得分: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 { }

添加了这两个简短的代码片段后,您现在就可以执行您在问题中描述的操作(只要在视图控制器实例中存在一个适当命名的nib):

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

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