objc_copyClassList 甚至无法枚举了?
objc_copyClassList not even enumerable anymore?
这是 and 的导数。
在 iOS 15,如果我只是尝试获取并枚举 objc 运行时的 类,等待 viewDidAppear 以确保没有初始化问题:
var count = UInt32(0)
var classList = objc_copyClassList(&count)!
print("COUNT \(count)")
print("CLASS LIST \(classList)")
for i in 0..<Int(count) {
print("\(i)")
classList[i]
}
在 Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1820e0cdc)
之前生成以下内容
COUNT 28353
CLASS LIST 0x000000010bf24000
0
1
2
2022-02-17 16:24:02.977904-0800 TWiG V[2504:705046] *** NSForwarding: warning: object 0x1dbd32148 of class '__NSGenericDeallocHandler' does not implement methodSignatureForSelector: -- trouble ahead
2022-02-17 16:24:02.978001-0800 TWiG V[2504:705046] *** NSForwarding: warning: object 0x1dbd32148 of class '__NSGenericDeallocHandler' does not implement doesNotRecognizeSelector: -- abort
除了获取值外,我不知道该怎么做。我不想打印它或任何东西,但它仍然失败。有没有我缺少的魔法?
(我没有开启强化运行时,XCode 13.2.1)
我确实在 Apple 论坛上得到了这个问题的答案。以下代码有效:
var count: UInt32 = 0
let classList = objc_copyClassList(&count)!
defer { free(UnsafeMutableRawPointer(classList)) }
let classes = UnsafeBufferPointer(start: classList, count: Int(count))
for cls in classes {
print(String(cString: class_getName(cls)))
}
我很惊讶为什么会这样,但我的却不行。 Here是相关解释:
I avoided this line in your code:
classList[i]
That line trigger’s Swift’s dynamic cast infrastructure,
which relies on -methodSignatureForSelector:, which isn’t implemented
by the __NSGenericDeallocHandler class.
So, the special sauce is this:
if you’re working with an arbitrary class you discover via the
Objective-C runtime, you have to be very careful what you do with it.
I recommend that you use Objective-C runtime calls to interrogate the
class to make sure it behaves reasonably before you let it ‘escape’
into code that you don’t control, like the Swift runtime.
In my example I used the Objective-C runtime routine class_getName to
get the class name, but there are a bunch of other things that you can
do to identify that you’re working with a reasonable class before you
let it escape into general-purpose code, like the Swift runtime.
这是
在 iOS 15,如果我只是尝试获取并枚举 objc 运行时的 类,等待 viewDidAppear 以确保没有初始化问题:
var count = UInt32(0)
var classList = objc_copyClassList(&count)!
print("COUNT \(count)")
print("CLASS LIST \(classList)")
for i in 0..<Int(count) {
print("\(i)")
classList[i]
}
在 Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1820e0cdc)
COUNT 28353
CLASS LIST 0x000000010bf24000
0
1
2
2022-02-17 16:24:02.977904-0800 TWiG V[2504:705046] *** NSForwarding: warning: object 0x1dbd32148 of class '__NSGenericDeallocHandler' does not implement methodSignatureForSelector: -- trouble ahead
2022-02-17 16:24:02.978001-0800 TWiG V[2504:705046] *** NSForwarding: warning: object 0x1dbd32148 of class '__NSGenericDeallocHandler' does not implement doesNotRecognizeSelector: -- abort
除了获取值外,我不知道该怎么做。我不想打印它或任何东西,但它仍然失败。有没有我缺少的魔法?
(我没有开启强化运行时,XCode 13.2.1)
我确实在 Apple 论坛上得到了这个问题的答案。以下代码有效:
var count: UInt32 = 0
let classList = objc_copyClassList(&count)!
defer { free(UnsafeMutableRawPointer(classList)) }
let classes = UnsafeBufferPointer(start: classList, count: Int(count))
for cls in classes {
print(String(cString: class_getName(cls)))
}
我很惊讶为什么会这样,但我的却不行。 Here是相关解释:
I avoided this line in your code:
classList[i]
That line trigger’s Swift’s dynamic cast infrastructure, which relies on -methodSignatureForSelector:, which isn’t implemented by the __NSGenericDeallocHandler class.
So, the special sauce is this:
if you’re working with an arbitrary class you discover via the Objective-C runtime, you have to be very careful what you do with it. I recommend that you use Objective-C runtime calls to interrogate the class to make sure it behaves reasonably before you let it ‘escape’ into code that you don’t control, like the Swift runtime.
In my example I used the Objective-C runtime routine class_getName to get the class name, but there are a bunch of other things that you can do to identify that you’re working with a reasonable class before you let it escape into general-purpose code, like the Swift runtime.