我在Swift上遇到了非常奇怪的崩溃。
Xcode 11.3.1
Swift 5
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)
。效果很好。
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)
。效果很好。
这是一个快速的错误吗?
我认为您滥用了objc_setAssociatedObject
。该文档说:
使用给定的键和关联策略为给定的对象设置关联值。
这里的重点是您需要一个对象,而不是一个class。
运行时函数objc_allocateClassPair
和objc_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