次のようなプロトコル拡張を使用して、いくつかの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
私は100%ポジティブになることはできませんが、これが起こっていると私が信じていることです:
プロトコル拡張機能には、ObjC
からアクセスできません。 UITextFieldDelegate
はObjC
プロトコルであるため、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 {
}
わかりました。別の問題を検討していることに気付きました。これはコンパイルされますが、機能せず、問題は動的ディスパッチです。メソッドを@objc
またはdynamic
で追加しようとすると、コンパイラは、クラスを除いて、この方法でディスパッチできないことを警告します。プロトコル例外がこれに準拠していないため、ObjCがメッセージ送信をディスパッチすると、拡張機能で実装が見つかりません。
Swiftは常に更新されているため、この回答が当てはまるのは次のとおりです。
Swift 2.0 Xcode 7 GM
ここでの良い議論、そしてまさにこの時点で私が疑っていること。ここで言及されていないもう1つのこと-おそらくこれは、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")
}
}
拡張機能のSwift生成されたヘッダーに以下を生成します:
@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ヘッダーに以下を生成します:
Swift_PROTOCOL("_TtP8MyApp27MyTextFieldDelegateProtocol_")
@protocol MyTextFieldDelegateProtocol <UITextFieldDelegate>
@end
実装はまったく表示されないため、プロトコル拡張の実装がobj-cからサポートされていないことを意味しているようです。また、誰かがここでその質問をしているのを見つけました(まだ答えはありませんが): Can Swift Objective-cでアクセスされるプロトコルの拡張機能で定義されたメソッド
残念ながら、この制限に関する公式のAppleドキュメントはまだ見つかりません。