2015-04-27 48 views
14

我有UIView的一個具體子類實現的協議斯威夫特 - 我怎樣才能在一個具體子類

protocol SomeProtocol { 
    var property : Int 
} 
    extension UIView : SomeProtocol { 
     var property : Int { 
     get { 
      return 0 
     } 
     set { 
      // do nothing 
     } 
     } 
    } 

延長我想重寫此擴展方法重載的擴展方法:

class Subclass : UIView, SomeProtocol { 
    var _property : Int = 1 
    var property : Int { 
    get { return _property} 
    set(val) {_property = val} 
    } 
} 

我設置了斷點,並看到擴展方法被調用,而不是具體的子類方法:

var subclassObject = Subclass() 

someObject.doSomethingWithConcreteSubclassObject(subclassObject) 

// other code; 

fun doSomethingWithConcreteSuclassObject(object : UIView) { 
    var value = object.property // always goes to extension class get/set 
} 
+0

我也嘗試添加重寫,但超類沒有此屬性 –

+2

Wich Swift版本您使用?在Swift 1.2和Xcode 6.3.1中,當您嘗試覆蓋_extension_屬性時,出現以下編譯時錯誤:「來自擴展的聲明不能被覆蓋」,並且_yet_暗示他們將來會出現。 –

+0

有趣,所以它看起來像這個功能即將在未來的版本。 –

回答

12

由於others have noted,斯威夫特沒有(還)允許您覆蓋在一個類擴展聲明的方法。然而,即使/有時候Swift允許你重寫這些方法,我也不確定你是否會得到你想要的行爲。

考慮Swift如何處理協議和協議擴展。給定一個協議來打印一些metasyntactic變量名:

protocol Metasyntactic { 
    func foo() -> String 
    func bar() -> String 
} 

的擴展,提供默認的實現:

extension Metasyntactic { 
    func foo() -> String { 
     return "foo" 
    } 

    func bar() -> String { 
     return "bar" 
    } 
} 

這符合協議的類:

class FooBar : Metasyntactic { 
    func foo() -> String { 
     return "FOO" 
    } 

    func bar() -> String { 
     return "BAR" 
    } 
} 

斯威夫特將使用動態調度調用適當的實現foo()bar() ba sed的每個變量的運行時類型而不是由編譯器推斷類型:

let a = FooBar() 
a.foo() // Prints "FOO" 
a.bar() // Prints "BAR" 

let b: Metasyntactic = FooBar() 
b.foo() // Prints "FOO" 
b.bar() // Prints "BAR" 

但是,如果我們延長該協議進一步增加了一種新方法:

extension Metasyntactic { 
    func baz() -> String { 
     return "baz" 
    } 
} 

如果我們覆蓋我們的新方法,在符合協議的類:

class FooBarBaz : Metasyntactic { 
    func foo() -> String { 
     return "FOO" 
    } 

    func bar() -> String { 
     return "BAR" 
    } 

    func baz() -> String { 
     return "BAZ" 
    } 
} 

斯威夫特將現在使用靜態調度調用基於由編譯器推斷類型的相應實施baz()

let a = FooBarBaz() 
a.baz() // Prints "BAZ" 

let b: Metasyntactic = FooBarBaz() 
b.baz() // Prints "baz" 

亞歷山德羅·薩拉薩爾有a fantastic blog post explaining this behavior in depth,但我只想說,斯威夫特只使用在原協議中聲明的方法的動態調度,不在協議擴展中聲明的方法的。我想,類擴展也是如此。

+0

非常棒的答案,謝謝。 – OhadM

-3

我覺得你忘了重寫你的子類中的超類屬性:

class Subclass : UIView { 
    var _property : Int = 1 
    override var property : Int { 
     get { return _property} 
     set(val) {_property = val} 
    } 
} 
+0

我也嘗試過。它會得到一個語法錯誤:「屬性不會覆蓋任何超類的屬性」 –

+0

這很奇怪。看起來像你的子類不能訪問超級的屬性。他們是否在同一個源文件中聲明?你可能不得不明確宣佈公開。 –

+1

看看http://stackoverflow.com/questions/27109006/can-you-override-between-extensions-in-swift-or-not-compiler-seems-confused – Moritz

0

看起來你可以覆蓋第2個超類屬性的屬性。例如,您可以通過擴展UILabel以覆蓋frame財產UIView來訪問UIView財產。此示例對我的作品在Xcode 6.3.2

extension UILabel { 

    override public var frame: CGRect { 

     didSet { 
      println("\(frame)") 
     } 
    } 
} 
0

我知道這個問題已經問了一段時間了。但是對於尋找更簡單方法的人來說,這將非常方便。有一種重寫擴展方法的方法。我知道它有點不好意思,但它很好地完成了這項工作。

如果用@objc

@objc protocol MethodOverridable { 
    func overrideMe() 
} 

聲明你的協議在擴展

extension MainClass: MethodOverridable { 
    func overrideMe() { 
     print("Something useful") 
    } 
} 

子類 - 你可以能夠覆蓋它在你的子類。它像一個魔術般運作。那麼,當添加@objc時,並不是真的會暴露您的protocol to Objective-C及其Runtime。這可以讓你的子類覆蓋。

class SubClass: MainClass { 
    override func overrideMe() { 
      print("Something more useful") 
     } 
    }