【问题标题】:EXC_BAD_ACCESS on waitForExpectations while unit testing单元测试时 waitForExpectations 上的 EXC_BAD_ACCESS
【发布时间】:2017-04-20 03:55:41
【问题描述】:

考虑以下简化的结构:

class MyClass {
    weak var delegate: MyClassDelegate?
}

protocol MyClassDelegate: class {
    func goneWrong()
}

以及抛出 EXC_BAD_ACCESS (0x40dedeadbec0) 错误的测试用例:

class MyTest: XCTestCase {
    func test() {
        let exp = expectation(description: "Expecting a call")
        let a = MyClass()
        a.delegate = MyMockDelegate(exp: exp)

        // Thread 1: EXC_BAD_ACCESS(code=1, address=0x40dedeadbec0)
        waitForExpectations(timeout: 10)
    }

    class MyMockDelegate: MyClassDelegate {
        let exp: XCTestExpectation

        init(exp: XCTestExpectation) {
            self.exp = exp
        }

        func goneWrong() {
            self.exp.fulfill()
        }
    }
}

如果委托 var 声明正常,没有弱关键字,则不会抛出错误。问题是它需要弱才能避免真实代码(而不是测试用例)中的强引用循环。我该如何解决这个问题?

【问题讨论】:

  • 只需将您的委托模拟保存在一个常量中,以在当前词法范围内保持强引用:let delegate = MyMockDelegate(exp: exp)
  • 我注意到在 Xcode Playgrounds 中,当代理声明为弱时,这也往往会发生。
  • @werediver 我试过了,我也试过将它存储为测试类的属性,但我得到了同样的错误。
  • 无法从示例中重现。

标签: swift automatic-ref-counting xctest weak-references


【解决方案1】:

这是一个老问题,所以我相信你现在已经解决了,但为了未来的读者,问题是你已经将你的代表定义为weak(即允许它被设置到nil 并且对象在它们不是强引用时被释放)。但是您没有强烈引用您的 MyMockDelegate 实例:

let a = MyClass()
a.delegate = MyMockDelegate(exp: exp)

现在,我希望它在这种情况下优雅地 nil delegate 引用,我不知道您为什么在 0x40dedeadbec0 地址处出现错误,因为我没有。 (顺便说一句,我不认为0x40dedeadbec0 是一个真正的内存地址,而是一些内核开发人员的坏双关语之一。)

无论如何,如果您希望您的模拟委托能够工作,您需要保留对它的引用直到测试结束,例如:

class MyAppTests: XCTestCase {

    func test() {
        let exp = expectation(description: "Expecting a call")

        var delegate: MyMockDelegate? = MyMockDelegate(exp: exp)

        let a = MyClass()
        a.delegate = delegate

        // do something

        waitForExpectations(timeout: 10)

        delegate = nil
    }
}

或者,您可以在测试类中创建一个属性,以便在测试期间保持对委托的强引用。无论哪种方式,如果您不想让 weak 参考消失,您需要不止一个参考。

【讨论】:

  • 顺便说一句,有人知道0x40dedeadbec0 是什么意思吗?这个地址看起来很像那些双关语的异常代码(例如,“0xbad22222”= VOIP 尝试也经常失败(“2”);当看门狗进程杀死您的应用程序时,0x8badf00d =“吃了不好的食物”;等等),但我在任何地方都看不到对它的引用。而这个值,0x40dedeadbec0 由于记忆问题而出现得太频繁了,所以我猜这是某人对双关语的想法,但我在任何地方都找不到它的定义......
  • 例如我猜是“(填空)死了,因为”或“(填空)死了变成了零”,但不知道“40de”代表什么......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-27
  • 2019-12-16
  • 2020-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多