ios - 带有objc_setAssociatedObject和objc_registerClassPair的Swift奇怪的EXC_BAD_ACCESS崩溃

标签 ios swift crash exc-bad-access associated-object

我在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)。它工作正常。

情况二
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)。它工作正常。

这是一个迅速的错误吗?

最佳答案

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

Sets an associated value for a given object using a given key and association policy.



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

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

关于ios - 带有objc_setAssociatedObject和objc_registerClassPair的Swift奇怪的EXC_BAD_ACCESS崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62027812/

相关文章:

ios - 向 MKUserTrackingBarButtonItem 添加操作

ios - 移动到另一个 swift 文件时 UIAlertController 不显示

ios - DYLD_PRINT_STATISTICS 未显示任何内容

swift - 如何读取核心数据的Group By - swift

Android 应用程序在解析 JSON 时崩溃

ios - 我如何从 SEL 中获取参数类型

ios - 在 CoreBluetooth 中使用两个特性不起作用

ios - 无需 Segue 即可传递标签

ios - 此应用程序正在从后台线程修改自动布局引擎,这可能导致引擎损坏和奇怪的崩溃。

internet-explorer - OpenCart - 如果填写产品 SEO 关键字,OpenCart 在 IE 上崩溃