首页 > 解决方案 > Swift 协议行为

问题描述

假设我在 Swift 中有协议 FooProtocol ,其中一种方法具有默认实现:

protocol FooProtocol {
    func foo()
}

extension FooProtocol {
    func foo() {
        print("protocol")
    }
}

和具有强制转换实例的类 FooClass:

class FooClass : FooProtocol {
    func foo() {
        print("class")
    }
} 

let A = FooClass() as FooProtocol
A.foo()

正如预期的那样,“class”将打印在控制台中。但是,如果我将协议的 foo() 方法设为可选 - 将改为打印“协议”。

@objc protocol FooProtocol {
    @objc optional func foo() 
}

但是如果我调用 A.foo?() 而不是 A.foo() - "class" 将再次打印。

我想知道,仅出于理论目的,这里到底发生了什么?任何解释表示赞赏。

标签: swiftpolymorphismprotocols

解决方案


optional没有可选链接就不能调用协议方法。即如果你注释掉

extension FooProtocol {
    func foo() {
    ...

你尝试调用A.foo(),你会得到一个编译错误:

可选类型 '(() -> ())?' 的值 必须解包为 '() -> ()' 类型的值

如您所见,可选的签名甚至与非可选的不同。因此,通过调用A.foo(),您不是在调用您实现的方法,而是直接调用默认协议实现。

这也是有道理的,因为使用 Objective C进行插值的主要原因@objc optional是默认协议实现不可见。因此,依赖于 objc 函数的协议函数会在 swift 和 Objective c 上产生不同的结果,这是不希望的。

我不能说optional在同一功能上同时使用默认协议实现是否存在任何漏洞。但问题是:你真的需要它吗?

如果你关心插值,你需要为 Swift 和 Objective c 提供相同的解决方案,这意味着你需要基本的协议实现,Swift 和 objc 都可以继承

如果您不需要插值,则实际上不需要可选,并且可以单独依赖默认协议实现。


推荐阅读