2015-09-12 127 views
20

我嘗試添加使用協議擴展,像這樣一些UITextFieldDelegate的方法的默認行爲:SWIFT 2.0 - UITextFieldDelegate協議擴展不工作

extension ViewController: UITextFieldDelegate { 
    // Works if I uncommented this so I know delegates are properly set 
// func textFieldShouldReturn(textField: UITextField) -> Bool { 
//  textField.resignFirstResponder() 
//  return true 
// } 
} 

extension UITextFieldDelegate { 
    func textFieldShouldReturn(textField: UITextField) -> Bool { 
     textField.resignFirstResponder() 

     return true 
    } 
} 

正如你可能已經猜到,鍵盤永不解散。我看不出這裏的問題在哪裏。這是語言限制嗎?有人已經成功做到了嗎?

編輯:

由於@Logan建議,默認協議的方法實現不標記爲@objc協議工作。然而,UITextFieldDelegate具有以下特徵public protocol UITextFieldDelegate : NSObjectProtocol {...}

我已經測試默認實施NSObjectProtocol,它似乎正常工作:

protocol Toto: NSObjectProtocol { 
    func randomInt() -> Int 
} 

extension Toto { 
    func randomInt() -> Int { 
     return 0 
    } 
} 

class Tata: NSObject, Toto {} 

let int = Tata().randomInt() // returns 0 

回答

8

我不能100%肯定的,但這裏是我認爲正在發生的事情:

ObjC無法訪問協議擴展。由於UITextFieldDelegateObjC協議,因此它依賴於ObjC調度。就編譯器而言,默認實現中的方法是不可訪問的,儘管它們確實存在。

爲了澄清,我們可以擴展這些協議,如果它的真正的擴展和添加行爲。這種行爲只能在Swift中訪問,並且不應以任何方式出現問題。

問題是默認實現不是ObjC可訪問。

下面是一個定製版本的一個簡單的例子:

@objc protocol Test : class { 
    func someFunc() -> String 
} 

extension Test { 
    func someFunc() -> String { 
     return "" 
    } 
} 

// Fails here 'candidate is not @objc but protocol requires it` 
class Hi : NSObject, Test { 

} 

的Xcode提示追加@objc,但它會繼續提示這一遍又一遍基於下面我們的談話,直到你得到@objc @objc @objc Hi : ...

,我做了這似乎在工作。我不能完全解釋爲何尚未:

@objc public protocol Toto: UITextFieldDelegate { 
    optional func randomInt() -> Int 
} 

extension Toto { 
    func randomInt() -> Int { 
     return 0 
    } 
    func textFieldShouldReturn(textField: UITextField) -> Bool { 
     return false 
    } 
} 

class Tata: NSObject, Toto { 
} 

好吧,我意識到,我正在考慮一個不同的問題,雖然這編譯,它不會工作,這個問題是動態調度。如果嘗試附加方法w/@objcdynamic,編譯器會警告您不能以這種方式調度,除了類。由於協議異常與此不符,因此當ObjC分派發送消息時,它無法在您的擴展中找到實現。

由於斯威夫特不斷更新,這裏是當這個答案是適用的:

雨燕2.0的Xcode 7 GM

+0

'UITextFieldDelegate'簽名看起來像'公共協議UITextFieldDelegate:NSObjectProtocol {...}'。我只是測試協議的擴展來實現'NSObjectProtocol'協議,它似乎沒有問題。此外,如果我試圖擴展'@ obj'協議,編譯器是不是應該警告我? – Yaman

+0

@Yaman - 我們都知道編譯器的警告在Swift中並不完美,有時還不清楚。如果你超越「不符合」的範圍,至少在我的系統中,我還會得到一個'@ objc'警告,它會一直添加'@ objc',但從未解決問題。這個問題並沒有擴展ObjC協議,對於任何混淆感到抱歉。問題是創建依賴於ObjC可訪問性的默認行爲。只能在Swift中訪問的ObjC協議的擴展和添加方法很好。添加必須是ObjC可訪問的默認實現是導致問題的原因。 – Logan

+0

感謝這些精度。我也測試了實現'NSObjectProtocol'的協議的默認實現,並且也可以工作。是否聲明'NSObjectProtocol'等價於'@ objc'標記?也許'UITextFieldDelegate'協議被隱式標記爲'@ objc',但我的自定義協議實現'NSObjectProtocol'不? – Yaman

3

好這裏的討論,並且正是我在這一點上懷疑爲好。 在這裏沒有提到另外一件事 - 可能這可能是由於obj-c無法訪問Swift協議擴展實現的更廣泛問題。

例如,下列代碼:

class MyViewController: UIViewController, MyTextFieldDelegateProtocol { 
    @IBOutlet weak var textField: UITextField! 
    override func viewDidLoad() { 
     super.viewDidLoad() 
     textField.delegate = self 
    } 
} 
extension MyViewController: UITextFieldDelegate { 
    func textFieldDidBeginEditing(textField: UITextField) { 
     print("shouldChangeCharactersInRange called") 
    } 
} 

會生成在夫特生成的頭下面爲擴展:

@interface MyViewController (SWIFT_EXTENSION(MyApp)) <UITextFieldDelegate> 
- (void)textFieldDidBeginEditing:(UITextField * __nonnull)textField; 
@end 

然而,使用協議擴展如下(類似的交):

class MyViewController: UIViewController, MyTextFieldDelegateProtocol { 
    // ... 
} 

@objc protocol MyTextFieldDelegateProtocol: UITextFieldDelegate {} 
extension MyTextFieldDelegateProtocol { 
    func textFieldDidBeginEditing(textField: UITextField) { 
     print("shouldChangeCharactersInRange called") 
    } 
} 

在Swift標頭中爲p生成以下代碼rotocol:

SWIFT_PROTOCOL("_TtP8MyApp27MyTextFieldDelegateProtocol_") 
@protocol MyTextFieldDelegateProtocol <UITextFieldDelegate> 
@end 

該實現根本不可見,所以它似乎暗示協議擴展實現不支持從obj-c。我也發現有人在這裏問這個問題(雖然還沒有答案): Can Swift Method Defined on Extensions on Protocols Accessed in Objective-c

不幸的是,我還沒有找到任何關於這個限制的官方蘋果文檔。