aun*_*nnn 12 generics ios swift
假设我有一个带有指定初始值设定项的自定义UIView子类:
class MyView: UIView {
init(custom: String) {
super.init(frame: .zero)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Run Code Online (Sandbox Code Playgroud)
正如预期的那样我不能打电话MyView(frame: .zero),因为它是不会自动继承从UIView.
然后假设我有一个视图构建器类:
class Builder<V: UIView> {
func build() -> V? {
// Check if can call init(frame:) or not
if V.instancesRespond(to: #selector(V.init(frame:))) {
return V.init(frame: .zero) // <-- Crash here, because the check doesn't work
} else {
return nil
}
}
}
Run Code Online (Sandbox Code Playgroud)
在这里我首先检查自定义视图V是否有init(frame:),如果是,则调用它.
但是,它不起作用,Builder<MyView>().build()会崩溃:
致命错误:对类'__lldb_expr_14.MyView'使用未实现的初始化程序'init(frame :)'
V.instancesRespond(to: #selector(V.init(frame:)))总是返回true,使这个检查无用.(或者我错误地使用了它?)
问题:如何检查通用视图类是否V实际响应init(frame:)?
更新1:
我也尝试V.responds(to: #selector(V.init(frame:)))过@kamaldeep和@Pranav指出.但是,false无论我是否重写init(frame :) ,它总是返回MyView.
更新2:我正在尝试做什么:
为了更清楚,我正在构建一个自动从这个枚举初始化的框架UIView:
enum ViewBuildMethod {
case nib
case nibName(String)
case frame(CGRect)
case custom(() -> UIView)
}
Run Code Online (Sandbox Code Playgroud)
并且要与框架一起使用的视图必须采用此协议并指定如何构建:
protocol SomeViewProtocol where Self: UIView {
// ... other funcs
static func buildMethod() -> ViewBuildMethod
}
Run Code Online (Sandbox Code Playgroud)
问题是我希望它override init(frame:)是可选的,并允许自定义指定的初始化程序(如in MyView).然后,fatalError当init(frame:)(未间接)在尚未覆盖它的视图上使用(间接)时,发出错误消息.这表明非法使用框架(如MyView的buildMethod回报.frame(.zero)),不能在编译时检查:
class MyView: UIView, SomeViewProtocol {
init(custom: String) {
super.init(frame: .zero)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
// ILLEGAL!!
static func buildMethod() -> ViewBulidMethod {
return .frame(.zero) // <-- Illegal, the framework will call V.init(frame: .zero) eventually
}
// LEGAL
// static func buildMethod() -> ViewBuildMethod {
// return .custom({ () -> UIView in
// return MyView(custom: "hello")
// })
// }
}
Run Code Online (Sandbox Code Playgroud)
错误消息可能是这样的V.init(frame:) is called indirectly but V doesn't override this designated initializer. Please override init(frame:) to fix this issue.我可以像上面那样让它崩溃,但是如果我能在这之前添加一些有意义的消息,那就更清楚了.
由于Swift不会自动从中继承,UIView因此无法检查您的类是否实现了init(frame:)构造函数.
我想instancesRespond(to:)回来true,因为它正在检查你的类是否符合消息调度的这条消息.但是,Swift对类中声明的方法使用Table调度.因此,此检查将与Objective-C一起使用,但不适用于Swift
所以,要实现你想要的,你可以使用 protocol
创建Buildable具有init(frame: CGRect)方法的协议
protocol Buildable {
init(frame: CGRect)
}
Run Code Online (Sandbox Code Playgroud)
使您的班级符合此协议
class MyView: UIView, Buildable {...}
Run Code Online (Sandbox Code Playgroud)
现在init(frame:)你的班级需要方法.将您的Builder类的泛型类型更改为Buildable
现在你的课可能是这样的
class Builder<V: Buildable> {
func build() -> V? {
return V(frame: .zero)
}
}
Run Code Online (Sandbox Code Playgroud)
现在,当你能够构建你的视图时Builder<MyView>().build(),如果你的课程不能确认Buildable协议,你将收到compile-time错误:
class SecondView: UIView {
init(custom: String) {
super.init(frame: .zero)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Builder<SecondView>().build()
Run Code Online (Sandbox Code Playgroud)
将抛出编译时错误:
error: type 'SecondView' does not conform to protocol 'Buildable'
Builder<SecondView>().build()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
311 次 |
| 最近记录: |