2

我在 Swift 上遇到了一个非常奇怪的崩溃。

Xcode 11.3.1

斯威夫特 5

情况1

class TestObject {
    var deinitExecution: (() -> Void)?
    deinit {
        // comment this to avoid crash
        deinitExecution?()
    }
}
private var associatedDynamicTagHandle: UInt8 = 0
class InterestTests: XCTestCase {
    func testExample() {
        guard let dynamicClass = objc_allocateClassPair(TestObject.self, "DynamicClass", 0) else {
            XCTFail()
            return
        }
        objc_registerClassPair(dynamicClass)
        objc_setAssociatedObject(dynamicClass, &associatedDynamicTagHandle, true, .OBJC_ASSOCIATION_ASSIGN)
    }
}

在此处输入图像描述

如果我删除了代码deinitExecution?()objc_setAssociatedObject(dynamicClass, &associatedDynamicTagHandle, true, .OBJC_ASSOCIATION_ASSIGN). 它工作正常。

案例2

class TestObject {
}
private var associatedDynamicTagHandle: UInt8 = 0
class InterestTests: XCTestCase {
    func testExample() {
        guard let dynamicClass = objc_allocateClassPair(TestObject.self, "DynamicClass", 0) else {
            XCTFail()
            return
        }
        objc_registerClassPair(dynamicClass)
        objc_setAssociatedObject(dynamicClass, &associatedDynamicTagHandle, true, .OBJC_ASSOCIATION_ASSIGN)
        let method = class_getInstanceMethod(dynamicClass, NSSelectorFromString("aName"))
        print("method: \(String(describing: method))")
    }
}

在此处输入图像描述

如果我删除了代码objc_setAssociatedObject(dynamicClass, &associatedDynamicTagHandle, true, .OBJC_ASSOCIATION_ASSIGN)。它工作正常。

这是一个快速的错误吗?

4

1 回答 1

1

我认为你误用objc_setAssociatedObject. 文档说:

使用给定键和关联策略为给定对象设置关联值。

这里的关键点是您需要一个对象,而不是一个

运行时函数只是创建新的运行时类,而不是对象objc_allocateClassPairobjc_registerClassPair要获取一个对象,您可以使用NSClassFromString、调用init()然后将标签与它关联。

一个完整的运行示例可能是(只是一个控制台程序,没有单元测试):

import Foundation

class TestObject {
    var deinitExecution: (() -> Void)?

    required init() {
        print ("TestObject.init()")
    }
    deinit {
        print ("TestObject.deinit()")
        deinitExecution?()
    }
}
private var associatedDynamicTagHandle: UInt8 = 0
class InterestTests {
    func testExample() {
        guard let dynamicClass = objc_allocateClassPair(TestObject.self, "DynamicClass", 0) else {
            print("oops")
            return
        }
        objc_registerClassPair(dynamicClass)
        let toClass = NSClassFromString("DynamicClass") as! TestObject.Type
        let obj = toClass.init()
        obj.deinitExecution = { print ("deinitExecution") }
        objc_setAssociatedObject(obj, &associatedDynamicTagHandle, true, .OBJC_ASSOCIATION_ASSIGN)
    }
    deinit {
        print ("InterestTests.deinit()")
    }
}

InterestTests().testExample()

具有以下输出:

TestObject.init()
one
TestObject.deinit()
deinitExecution
InterestTests.deinit()
Program ended with exit code: 0

于 2020-05-26T20:16:32.573 回答