Xcode 8 个警告 "Instance method nearly matches optional requirement"

Xcode 8 Warning "Instance method nearly matches optional requirement"

我在 Xcode 8 中将我的 (macOS) 项目转换为 Swift 3 并且我在 swift 类 中实现的几个委托方法收到以下警告:

Instance method 'someMethod' nearly matches optional requirement of protocol 'protocolName'

我为几个 NSApplicationDelegate 方法得到了这个,比如 applicationDidFinishLaunchingapplicationDidBecomeActive:

但也适用于 tableViewSelectionDidChange 的实现:

我使用代码完成来插入方法签名,并尝试从 SDK-headers 中复制它们以排除拼写错误。警告不会消失,也不会调用这些方法。

我在这里错过了什么?

我们就此问题联系了 Apple 开发人员技术支持 (DTS)。 他们回答说这是 Xcode 8. 中的一个 错误。

我们提交了错误报告,希望尽快更新。 (Apple 错误报告 ID:28315920)。

如果您遇到类似问题,还请file a bug report(指我们的),以便苹果工程师看到它不是一个案例。


更新 Xcode ≥ 8.1

问题现在似乎已解决,至少对于我们在项目中使用的委托方法而言是这样。

经过几个小时的搜索,我找到了这个 -

您可以通过在函数

的 objective-c 声明前加上前缀来解决此错误
@objc(tableViewSettingsDidChange:notification:)
func tableViewSettingsDidChange(_ notification:Notification)

郑重声明,我在实现 WKWebView 的 didFailProvisionalNavigation 委托方法时遇到了同样的问题。解决方案是添加@objc 声明 and 将最后一个参数的类型从 Error 更改为 NSError:

@objc(webView:didFailProvisionalNavigation:withError:)
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: NSError) {
    // handle error
}

只是为了澄清这个过于复杂的解决方法:有人能看出为什么在执行操作时下面的内容不是 firing/working 吗?

extension AppDelegate: UNUserNotificationCenterDelegate {
    @objc(userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:)
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        print("RESPONSE FROM NOTIFICATION!")

        switch response.actionIdentifier {
        case "reply":
            print("Reply action received!")
        case "ignore":
            print("Ignore action received!")
        default: print("Error - Unknown action received!")
            break
        }
    }
}

对于 xcode 8.1 >= 和 swift 3,

在方法的开头添加@nonobjc 以消除此警告。

NSError 桥接到 Swift 时出现此警告的另一个原因:

鉴于此 Objective-C 委托方法:

- (void)myService:(id<MYService>)myService didFailForSomeReason:(NSError *)error;

自动生成这个Swift方法:

public func myService(_ myService: MYService!, didFailForSomeReason error: Error!)

已显示警告。

在我的例子中,原因是我的 class 有自己的 Error 类型,所以签名解析为 MyClass.Error 而不是 Swift.Error。解决方案是通过将错误参数更改为 Swift.Error:

来完全键入错误参数
public func myService(_ myService: MYService!, didFailForSomeReason error: Swift.Error!)

这是为我修复的。

我在某些代码中收到了相同的警告,我确定我最初在编辑器中输入并允许它自动完成。随后,我返回并重新查看警告,并尝试在我现有的函数之后再次键入相同的函数。当我再次输入函数名称时,我的函数签名发生了变化并且参数与 Xcode 预期的完全匹配并且警告被抑制了。

因此,如果您想快速进行完整性检查,请帮自己一个忙,再尝试输入一次该函数,看看参数类型是否发生变化。这可能就是你所需要的。

您可能会收到此错误的一个原因与方法访问修饰符有关。例如,如果您没有将函数定义为 public。因此,对于 CLLocationManagerDelegate 案例中的方法,更改:

func locationManager(_ manager: CLLocationManager,
                     didChangeAuthorization status: CLAuthorizationStatus)

至:

public func locationManager(_ manager: CLLocationManager,
                            didChangeAuthorization status: CLAuthorizationStatus)

(即使方法 public)消除警告并按预期调用该方法。请注意,自动完成不会在方法上放置 public 访问修饰符。

对我来说问题是自定义的 Error class
基本上我有自己的 class 名称 Error 并且编译器正在考虑 delegate method 作为本地方法

我刚刚更改了我自己的 class 名字,它成功了。因此,只需确认您在函数

中没有任何 class 名称相同

这让我原地转了一圈。这是因为我创建了自己的 Notification class。一旦我更改了这个 class 名称(不要重构,因为它会更改 objc 通知参数),所有错误都消失了