【问题标题】:Swift EXC_BAD_ACCESS with default implementation defined in protocol extensionSwift EXC_BAD_ACCESS 与协议扩展中定义的默认实现
【发布时间】:2017-12-20 16:54:17
【问题描述】:

以下 Playground 代码在从 1(Xcode 9.2,Swift 4)调用时会导致第 2 行崩溃(EXC_BAD_ACCESS)。在我看来,这是完全有效的代码。

当 Observable 扩展被移除并且 addObserver 方法被定义在实现类中(TestObservableImpl)时,崩溃消失了。

如果协议 TestObservableListener 被移除,并且在协议 TestObservable 中将 TestObserverImpl 用作 Observer 的类型约束,崩溃也会消失。

有没有人知道为什么,或者这只是一个 Swift 错误?

public protocol Observable: class {
    associatedtype Observer: AnyObject
    var observers: [Observer] { get set }
    func addObserver(_ observer: Observer) -> Void
}

public extension Observable {
    public func addObserver(_ observer: Observer) -> Void {
        observers.append(observer)
    }
}

protocol TestObservableListener: class {
    func bla()
}

protocol TestObservable: Observable where Observer == TestObservableListener {
}

class TestObservableImpl: TestObservable {
    typealias Observer = TestObservableListener
    public var observers = [Observer]()
    func broadcast() {
        for observer in observers {
            //2
            observer.bla()
        }
    }
}

class TestObserverImpl: TestObservableListener {
    func bla() {
        print("bla")
    }
}

let observable = TestObservableImpl()
let observer = TestObserverImpl()
observable.addObserver(observer)
//1
observable.broadcast()

【问题讨论】:

  • 快速浏览了一下,这也将解决问题:(observer as! TestObserverImpl).bla() 所以看起来可怜的旧运行时很难确定观察者对象的实际类型。
  • 你说得对,它确实修复了崩溃,但是在实际场景中,TestObservableImpl 无法使用具体类型(需要在协议上工作)。
  • 我意识到这可能不是一个解决方案,这就是为什么我将它添加为评论而不是答案我只是认为它可能指向一个原因,因为我没有时间进一步调查。

标签: swift crash swift4


【解决方案1】:

您是否尝试过像这样在associatedtype Observer 之后删除AnyObject

public protocol Observable: class {
  associatedtype Observer
  var observers: [Observer] { get set }
  func addObserver(_ observer: Observer) -> Void
}

我测试过,它工作正常。

我认为您的条件 Observer == TestObservableListener 将在 AnyObjectProtocol 之间进行比较,导致出现该错误。

【讨论】:

  • 这很好,但对于我的实现,Observer 必须限制为 AnyObject,因为它需要定义引用相等运算符 (===)
  • @WernerAltewischer 我不完全理解你的答案。 observerTestObservableListener 的类型。你可以比较一下:for observer in observers { print(observer === observer) }
  • 真正的实现只涉及 Observable 协议,示例的其余部分只是为了澄清我的观点。一般来说,关联的观察者需要是一个对象,因为它需要是弱可引用的(在示例中,观察者只是一个数组,但实际上它是一个弱引用其对象的序列实现)
  • 无论如何我都会给你一个赞成票,因为这是一个有用的建议
  • @WernerAltewischer 我试图准确地理解你想要什么。你的协议符合类protocol TestObservableListener: class,我认为这意味着任何匹配Observer == TestObservableListenerObserver 都将是一个对象,对吧?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多