我想创建一个NSView子类,通过将拖放重定向到其视图控制器来处理拖放。所以我必须覆盖NSView子类中的NSDraggingDestination协议方法。在那里,我想检查视图控制器实现是否支持方法并调用它,或者如果不支持调用基类实现。第一部分看起来很容易通过可选链接,但我如何检查方法是否在超类中实现?例如,这就是我为拖拽方法而提出的。如果视图控制器没有实现draggingEnded方法,它会在块内部发生运行时崩溃。
class ControllerChainedView: NSView {
@IBOutlet weak var chainedController: NSViewController!
override func draggingEnded(sender: NSDraggingInfo?) {
let destination = chainedController as! NSDraggingDestination
if !(destination.draggingEnded?(sender) != nil) {
super.draggingEnded(sender);
}
}
}
将内部的行更改为super.draggingEnded?(sender);给出编译器错误。 (postfix的操作数'?'应该有可选类型;类型是'(NSDraggingInfo?) - > Void')
类似的draggingEntered方法没有问题,因为它似乎在NSView中实现。 所以问题是如何检测一个人是否可以调用超级方法?
答案 0 :(得分:0)
如果您的super
基于NSObject
,您仍然可以这样使用respondsToSelector:
:
if super.respondsToSelector("draggingEnded:") {
super.draggingEnded(sender)
}
更新 - 基于第一次Alex评论
取决于。一般情况下不行,你不能在没有调用它的情况下使用可选链接来执行此操作。
但你可以做的是检查功能是否被调用。但同样,仅在特定情况下。必须是@objc
协议,必须基于NSObject
并且可选函数的返回值不能是可选的。
检查以下示例。
@objc protocol Opt {
optional func implemented() -> Void
optional func notImplemented() -> Void
}
class Object: NSObject, Opt {
func implemented() {}
}
let o = Object() as Opt
let implementedCalled = o.implemented?() != nil // == true
let notImplementedCalled = o.notImplemented?() != nil // == false
在这种特殊情况下,implementedCalled
设置为true
。换句话说,您至少可以检查方法是否被调用。这是因为可选链接,因为o.implemented
返回类型为Void
,o.implemented?()
会返回Void?
。
您也可以这样做......
if o.implemented != nil {
// Function is implemented AND implemented WAS CALLED
} else {
// Function is not implemented
}
...但是不要忘记它不是检查函数是否已实现,它是 - 如果实现了函数,则调用它并返回.Some(Void)
或.None
如果它没有实现。
在您的特定情况下,您可以这样做:
override func draggingEnded(sender: NSDraggingInfo?) {
let destination = chainedController as! NSDraggingDestination
if destination.draggingEnded?(sender) == nil {
// .None returned - method not implemented in destination
// draggingEnded is called in super only if it's implemented
// ignore result of type Void?
super.draggingEnded?(sender)
}
}
如果可选功能的返回类型不是Void
,而是例如String
,则其行为方式相同。
@objc protocol Opt {
optional func name() -> String
}
class Object: NSObject, Opt {
func name() -> String { return "Object" }
}
let o = Object() as Opt
let n: String? = o.name?() // n contains "Object"
如果name
未实施,则n
将包含None
。
到目前为止,这么好。我们可以检查是否为Void
和String
(或任何其他类型)调用了函数。
但是如果返回类型是可选的呢?例如String?
。
@objc protocol Opt {
optional func name() -> String?
}
class Object: NSObject, Opt {
func name() -> String? { return nil }
}
class Object2: NSObject, Opt {
}
let o = Object() as Opt
let n = o.name?()
let o2 = Object2() as Opt
let n2 = o2.name?()
Object
实现了name
,但它返回nil
而Object2
根本没有实现name
。但n
和n2
都包含nil
。换句话说,如果返回类型是可选的,我们无法检查函数是否已实现。
正如你所看到的,这很棘手。有时它适合您的需求,有时不适合。如果您确定自己的对象基于NSObject
,请坚持.respondsToSelector
以确保安全。然后,您可以忽略所有这些条件和案例。
如果您的目标是只调用函数并且您不关心它是否真的实现了,如果您对结果不感兴趣,可以使用?
来完成。
答案 1 :(得分:0)
由于可选语法?
不适用于super
,因此您必须明确检查超类是否实现该方法。
if NSView.instancesRespondToSelector("draggingEnded:") {
super.draggingEnded(sender)
}