Dai*_*hen 3 objective-c objective-c-runtime ios
我在其中一个项目中发现了一个奇怪的问题.我的目标是在运行时添加一个带有新协议的新类.我拿出了部分代码来重现这个问题.
- (void)viewDidLoad {
[super viewDidLoad];
[self registerClass:@"Daidouji"];
[self protocolInClass:NSClassFromString(@"Daidouji")];
}
- (void)registerClass:(NSString *)className {
Class superclass = (Class)objc_getClass("UIViewController");
Class newClass = objc_allocateClassPair(superclass, [className UTF8String], 0);
Protocol *newProtocol = objc_allocateProtocol([@"ViewController" UTF8String]);
objc_registerProtocol(newProtocol);
class_addProtocol(newClass, newProtocol);
objc_registerClassPair(newClass);
}
- (void)protocolInClass:(Class)cls {
unsigned count;
__unsafe_unretained Protocol **protocols = class_copyProtocolList(cls, &count);
if (count) {
NSLog(@"%@", [NSString stringWithUTF8String:protocol_getName(protocols[0])]);
}
free(protocols);
}
Run Code Online (Sandbox Code Playgroud)
在iPhone5(armv7)或iOS模拟器(i386/x86_64)中,NSLog可以很好地打印ViewController.在iPhone5s(arm64)中,应用程序将崩溃或打印(null).
我发现的第一个解决方案是添加protocol_getName之类的
- (void)registerClass:(NSString *)className {
Class superclass = (Class)objc_getClass("UIViewController");
Class newClass = objc_allocateClassPair(superclass, [className UTF8String], 0);
Protocol *newProtocol = objc_allocateProtocol([@"ViewController" UTF8String]);
objc_registerProtocol(newProtocol);
// add here
protocol_getName(newProtocol);
class_addProtocol(newClass, newProtocol);
objc_registerClassPair(newClass);
}
Run Code Online (Sandbox Code Playgroud)
但为什么?有相关性吗?
从我的朋友那里找到的第二个解决方案是添加__unsafe_unretained之类的
- (void)registerClass:(NSString *)className {
Class superclass = (Class)objc_getClass("UIViewController");
Class newClass = objc_allocateClassPair(superclass, [className UTF8String], 0);
// add here
__unsafe_unretained Protocol *newProtocol = objc_allocateProtocol([@"ViewController" UTF8String]);
objc_registerProtocol(newProtocol);
class_addProtocol(newClass, newProtocol);
objc_registerClassPair(newClass);
}
Run Code Online (Sandbox Code Playgroud)
再一次,为什么?
我试图在objc运行时源代码中找到arm64/non-arm64之间的区别,但无济于事.我希望有人可以解释导致不同行为的根本原因.谢谢.
更新:直接从github RuntimeProtocolIssue下载演示代码
最后,我将这个问题发布到苹果论坛.很高兴收到苹果回复,
这是ARC与Objective-C运行时的错误.它已经修复,但我认为任何iOS版本都没有改变.
最安全的解决方案是在非ARC文件中调用objc_allocateProtocol()和objc_registerProtocol().你的unsafe_unretained修复也应该有效.添加对protocol_getName()的额外调用不是可靠的修复.
希望在遇到这个问题时帮助像我这样的人.
| 归档时间: |
|
| 查看次数: |
415 次 |
| 最近记录: |