我正在尝试在 Objective-C 上进行一些运行时编程。为了做到这一点,我重写了resolveClassMethod方法。
不幸的是,当 ARC 处于活动状态时,我在 clang 中遇到了一些编译错误:
错误:选择器“动态”没有已知的类方法
如果我在没有 ARC 的情况下使用 gcc 或 clang(通过-fno-objc-arc选项),一切正常,除了警告而不是错误。
我知道 ARC 需要知道调用的方法的名称,以弄清楚如何使用返回值管理内存(遵循方法名称约定)。但是如何在没有丑陋的performSelector调用而不是直接方法调用的情况下解决这个问题?
这是我的代码:
测试.m
#import "Test.h"
#import <objc/runtime.h>
NSString* dynamicImp(id slef, SEL _cmd)
{
NSLog(@"Dynamic method called");
return @"dynamicImp";
}
@implementation Test
- (NSString*)name
{
return @"John";
}
+ (BOOL)resolveClassMethod:(SEL)name
{
if (name == @selector(dynamic))
{
Class metaClass = objc_getMetaClass([NSStringFromClass([self class]) UTF8String]);
class_addMethod(metaClass, name, (IMP) dynamicImp, "@@:");
return YES;
}
return NO;
}
+ (IMP)methodForSelector:(SEL)aSelector
{
if (aSelector == @selector(dynamic))
{
return (IMP) dynamicImp;
}
else
{
return [super methodForSelector:aSelector];
}
}
- (BOOL)respondsToSelector:(SEL)aSelector
{
if (aSelector == @selector(dynamic))
{
return YES;
}
else
{
return [NSObject respondsToSelector:aSelector];
}
}
@end
测试.h
#import <Cocoa/Cocoa.h>
@interface Test : NSObject <NSObject> {
NSString *_name;
}
- (NSString*)name;
@end
主文件
#import <Cocoa/Cocoa.h>
#import <stdio.h>
#import "Test.h"
int main(int argc, char* argv[])
{
@autoreleasepool {
Test *test = [[Test alloc] init];
NSLog(@"Hello, %@", [test name]);
NSLog(@"How are you , %@", [Test dynamic]);
}
return 0;
}
没有 ARC 的 Gcc 或 clang
编译结果
main.m:13:36:警告:找不到类方法“+动态”(返回类型默认为“id”)
NSLog(@"How are you , %@", [Test dynamic]);
输出
2012-10-22 10:33:15.563 test-clang[957:707] 你好,约翰 2012-10-22
2012-10-22 10:33:15.565 test-clang[957:707] 动态方法称为 2012-10-22
2012-10-22 10:33:15.565 test-clang[957:707] 你好吗,dynamicImp
与 ARC 铿锵
编译结果
main.m:13:36:错误:选择器“动态”没有已知的类方法
NSLog(@"How are you , %@", [Test dynamic]);
PS:我不关心内存管理的那一刻,因为我的目标是在激活 ARC 的情况下编译这段代码。