将可选协议方法分配给变量的有趣混淆

  • 本文关键字:变量 协议 方法 分配 swift
  • 更新时间 :
  • 英文 :


假设我有一个UITextField。我想检查它的delegate是否已设置,如果已设置,请检查是否实现了特定的可选方法。如果实现了它,那么我需要调用它,否则执行回退操作。一种常见的方法是:

let field = // some UITextField instance
if let delegate = field.delegate, delegate.responds(to: #selector(UITextFieldDelegate.textField(_:shouldChangeCharactersIn:replacementString:))) {
if delegate.textField?(field, shouldChangeCharactersIn: someRange, replacementString: someString) == true {
// do something here
}
} else {
// Fallback action
}

这一切都奏效了。但后来我有一种尝试不同方法的冲动。我不想使用responds(to:),而是想将可选的委托方法分配给一个变量。我想出了以下实际可行的方法:

注意:以下代码需要iOS 15.0的部署目标才能编译。如果你将目标设置为iOS 16.0,那么它不会编译。不知道为什么。

if let delegate = field.delegate, let should = delegate.textField {
if should(field, field.selectedRange, title) {
// do something here
}
} else {
// Fallback action
}

虽然这有效,但我真的很困惑为什么它有效。

  1. let should = delegate.textField部分没有提及方法的参数
  2. UITextFieldDelegate协议有4个从textField开始的可选方法。这些是:
    • func textField(UITextField, shouldChangeCharactersIn: NSRange, replacementString: String) -> Bool
    • func textField(UITextField, editMenuForCharactersIn: NSRange, suggestedActions: [UIMenuElement]) -> UIMenu?
    • func textField(UITextField, willDismissEditMenuWith: UIEditMenuInteractionAnimating)
    • func textField(UITextField, willPresentEditMenuWith: UIEditMenuInteractionAnimating)

那么这是如何工作的呢?编译器怎么知道我指的是哪一个?事实上,它似乎只适用于碰巧是第一名的人。

对于其他3个委托方法,我找不到任何方法可以做到这一点。如果我真的想调用func textField(UITextField, editMenuForCharactersIn: NSRange, suggestedActions: [UIMenuElement]) -> UIMenu?方法,我不知道该怎么做。以下代码将不会编译:

if let delegate = field.delegate, let editMenu = delegate.textField {
let suggested = [UIMenuElement]()
if let menu = editMenu(field, field.selectedRange, suggested) {
}
}

这给出了错误:

无法将类型为"[UIMuElement]"的值转换为预期的参数类型"String">

if let menu = should(field, field.selectedRange, suggested) {行。这清楚地表明它是在假设func textField(UITextField, shouldChangeCharactersIn: NSRange, replacementString: String) -> Bool方法。

是否有语法(我缺少(允许我将特定的协议方法分配给变量?

目前,我将坚持尝试使用responds(to:),但我希望能解释一下将命名不明确的协议方法分配给变量的尝试是怎么回事,以及是否有方法指定参数以获得正确的分配。

我在SO上的搜索没有产生任何相关的问题/答案。

我的代码在一个iOS项目中,部署目标为iOS 15.0及更高版本,使用Xcode 14.0.1。Swift编译器设置是为Swift 5设置的。这段代码似乎没有以iOS 16.0的部署目标进行编译。奇怪的

您可以通过强烈键入或拼写参数来消除歧义。我们都不知道为什么您的代码在编译时没有歧义。这对我们不起作用。

if
let shouldChangeCharacters: (_, _, String) -> _ = field.delegate?.textField,
let editMenu: (_, _, Array) -> _ = field.delegate?.textField,
let willDismissEditMenu = field.delegate?.textField(_:willDismissEditMenuWith:),
let willPresentEditMenu = field.delegate?.textField(_:willPresentEditMenuWith:)
{ }

我不确定你的问题的实际答案,但我要说的是,如果我的目标是iOS 16,你的工作代码不会为我编译。我收到一个错误,上面写着:

error: ambiguous use of 'textField'
if let delegate = textField.delegate, let should = delegate.textField {
UIKit.UITextFieldDelegate:13:19: note: found this candidate
optional func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
UIKit.UITextFieldDelegate:23:19: note: found this candidate
optional func textField(_ textField: UITextField, editMenuForCharactersIn range: NSRange, suggestedActions: [UIMenuElement]) -> UIMenu?

但是,与其保留带有should变量的函数,为什么不将结果作为if语句的一部分展开呢?

类似这样的东西:

if let delegate = textField.delegate,
let should = delegate.textField?(field, shouldChangeCharactersIn: someRange, replacementString: someString) {
if should {
// perform some action
}
} else {
// perform fallback action
}

得到的逻辑应该是相同的。

最新更新