2015-04-14 21 views
0

我想創建一個處理拖放的NSView子類,方法是將其重定向到其視圖控制器。所以我必須在我的NSView子類中重寫NSDraggingDestination協議方法。在那裏,我想檢查視圖控制器實現是否支持方法並調用它,或者如果不支持調用基類實現。第一部分看起來很容易通過可選鏈接,但是如何檢查超類中是否實現了方法?例如,這就是我想出的draggingEnded方法。如果視圖控制器沒有實現draggingEnded方法,它會在塊內發生運行時崩潰。在超級調用swift可選協議方法

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);給出編譯器錯誤。 (後綴'?'的操作數應該有可選類型;類型是'(NSDraggingInfo?) - > Void')

說到類似的draggingEntered方法似乎沒有問題,因爲它似乎在NSView中實現。 所以問題是如何檢測是否可以調用超級或不超級?

回答

0

如果super基於NSObject,你仍然可以以這種方式使用respondsToSelector:

if super.respondsToSelector("draggingEnded:") { 
    super.draggingEnded(sender) 
} 

更新 - 基於1亞歷克斯評論

而定。一般來說不,你不能在不調用它的情況下使用可選的鏈接來完成此操作。

但是你可以做的是檢查函數是否被調用。但是,僅在特定情況下。必須爲@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

到目前爲止,一切都很好。我們可以檢查VoidString(或任何其他類型)是否被調用。

但是如果返回類型是可選的呢?例如,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,但它返回nilObject2沒有實現name可言。但nn2都包含nil。換句話說,如果返回類型是可選的,我們不能檢查函數是否被實現。

正如你所看到的,這很棘手。有時它適合你的需求,有時不適合。如果你確定你的物體是基於NSObject,堅持.respondsToSelector是安全的。您可以忽略所有這些情況和案例。

如果你的目標是隻是調用函數,如果它實現了,你不在乎它是否真的實現,如果你對結果沒有興趣,你可以用?來實現。

+0

是否可以使用swift optionals進行檢查?使用NSObject細節和swift似乎是多餘的。 –

+0

@AlexanderB我只是更新我的答案,更多細節。這不是多餘的,它與Objective-C和Swift的不同性質以及這兩種語言之間的合作。 – robertvojta

+0

嘗試super.draggingEnded?(發件人)是我嘗試的第一件事情,在問題結尾處查看。它不編譯(postfix'?'的操作數應該有可選類型;類型是'(NSDraggingInfo?) - > Void')。嘗試強制讓superDestination =超級,因爲NSDraggingDestination不能編譯。 –

0

由於可選語法?不適用於super您必須明確檢查超類是否實現該方法。

if NSView.instancesRespondToSelector("draggingEnded:") { 
    super.draggingEnded(sender) 
}