我是从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)
....
答案 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
子类现在都可以免费获得此功能;不需要继承。