使用objc_setAssociatedObject和objc_registerClassPair快速奇怪的EXC_BAD_ACCESS崩溃

问题描述 投票:1回答:1

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

Xcode 11.3.1

Swift 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)
    }
}

enter image description here

如果我删除了代码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))")
    }
}

enter image description here

如果我删除了代码objc_setAssociatedObject(dynamicClass, &associatedDynamicTagHandle, true, .OBJC_ASSOCIATION_ASSIGN)。效果很好。

这是一个快速的错误吗?

ios swift crash exc-bad-access associated-object
1个回答
0
投票

我认为您滥用了objc_setAssociatedObject。该文档说:

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

这里的重点是您需要一个对象,而不是一个class

运行时函数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

© www.soinside.com 2019 - 2024. All rights reserved.