在Swift协议上应用自我约束与在协议扩展上的区别

时间:2017-12-06 01:46:42

标签: ios swift

当我在协议本身上应用Self约束时,我遇到了一个奇怪的运行时错误,而当我将约束更改为协议的扩展时,代码按预期运行。我想知道是否有人可以帮助我解释差异,或者帮助我确认这是意外行为(即语言错误)。 这是不起作用的代码(它是在Playground中编写的,因此主要逻辑不在方法中):

class Foo {
    let val: Int

    init(_ val: Int) {
        self.val = val
    }
}

protocol IFooComparer where Self: Foo {
    func compareTo(other: Foo) -> Bool?
}

class Bar : Foo, IFooComparer {
    func compareTo(other: Foo) -> Bool? {
        guard let otherBar = other as? Bar else { return nil }

        return self.val < otherBar.val
    }
}

let foos: [Foo] = [
    Foo(1),
    Bar(2),
]
let newFoo = Bar(3)
for foo in foos {
    if let comparer = foo as? IFooComparer, let result = comparer.compareTo(other: newFoo) {
        print("\(foo.val): \(result)")
    } else {
        print("\(foo.val): Cannot compare")
    }
}

代码将在第一次循环迭代时成功,然后在第二次循环迭代时失败,它会抛出EXC_BAD_ACCESS。从我在调试器中收集的内容来看,在调用compareTo()之前,在循环体内创建的范围变量“comparer”似乎是一个有效的对象;但是在compareTo()中,“self”变量看起来像一个损坏/解除分配的对象,这会导致异常。 现在奇怪的是,如果我将协议定义更改为:

protocol IFooComparer {
    func compareTo(other: Foo) -> Bool?
}
extension IFooComparer where Self: Foo { }

代码运行正常。有人可以帮我解释一下这些差异吗?谢谢! P.S:我正在运行Xcode版本9.2(9C40b)

1 个答案:

答案 0 :(得分:1)

“有效”的方法实际上并没有完成相同的事情。由于该方法是在协议中声明的,而不是在扩展中声明的,因此不再需要解决约束。

使用这种逻辑,让我们向该扩展名添加一个方法,然后尝试查看它是否可以解决约束。

所以我们有这种工作方法:

protocol IFooComparer {
    func compareTo(other: Foo) -> Bool?
}
extension IFooComparer where Self: Foo { }

让扩展名添加一个新方法compare2

extension IFooComparer where Self: Foo {
    func compareTo2(other: Foo) -> Bool? {
        return nil
    }
}

现在,如果要使用此方法代替常规的compare,我们将拥有

if let comparer = foo as? IFooComparer,
   let result = comparer.compareTo2(other: newFoo)

这也不起作用,因为

  

'IFooComparer'不是'Foo'的子类型

这告诉我编译器在解决扩展中的约束时遇到问题。

当直接向协议本身指定约束时,也会发生同样的情况。

对此的一种解决方案是强制转换为实现协议的具体类,即Bar

protocol IFooComparer where Self: Foo {
    func compareTo(other: Foo) -> Bool?
}

for foo in foos {
    if let c = foo as? Bar, let result = c.compareTo(other: foo) {
    ...

基于此,我认为问题是在某些情况下编译器无法验证协议/扩展约束。不必与对协议本身设置约束这一事实有关。

不过,我很乐意对此进行精确的解释,但不确定为什么不能解决约束。