objc_copyClassList: 在更新到iOS 13.4 / XCode 11.4后崩溃EXC_BAD_INSTRUCTION的问题

4
更新至 iOS 13.4 / XCode 11.4 后,这段代码:
func getSubclassInfos() -> [ClassInfo] {
    let superObject = CityModel.self
    let superClassInfo = ClassInfo(superObject)

    var subclassList = [ClassInfo]()
    var count = UInt32(0)
    guard let classList = objc_copyClassList(&count) else {
        return subclassList
    }
    for i in 0..<Int(count) {
        let clazz = classList[i] // Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
        if let classInfo = ClassInfo(classList[i]),
            let superclassInfo = classInfo.superclassInfo,
            superclassInfo == superClassInfo
        {
            subclassList.append(classInfo)
        }
    }

    return subclassList
}

模拟器中的代码崩溃在let clazz = classList[i]这一行,报错为EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

这一行不是我的原始代码。它在这里只是为了表明下标越界导致崩溃,而不是ClassInfo(...)

你有什么建议吗?

(这段代码受列出一个类的所有子类的启示)


你是否已启用强化运行时?我认为那会限制一些 Objective-C 运行时的能力,但我不确定。值得研究一下。顺便说一句,你可以将整个 for 循环简化为一个简单的 map 调用。 - Alexander
没有强化运行时。 (是的,map会更优雅。我的旧代码) - Gerd Castan
这个问题(以及其他问题的要点)在iOS 15中失败了(运行时未加固)。它访问列表的2个元素,然后抛出异常:( - Travis Griggs
1个回答

8

注意: classList 这个名称明显不准确。返回的结果类型是 AutoreleasingUnsafeMutablePointer<AnyClass>?。首先将其转换为 UnsafeBufferPointer<AnyClass>,然后在其上进行处理:

func getSubclassInfos() -> [ClassInfo] {
    let superObject = CityModel.self
    let superClassInfo = ClassInfo(superObject)

    var count = UInt32(0)
    guard let classListPointer = objc_copyClassList(&count) else { return [] }

    return UnsafeBufferPointer(start: classListPointer, count: Int(count))
        .map(ClassInfo.init)
        .filter { $0 == superClassInfo }
}

1
这个可行,谢谢:return UnsafeBufferPointer(start: classListPointer, count: Int(count)) .compactMap(ClassInfo.init) .filter { $0.superclassInfo == superClassInfo } - Gerd Castan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接