私はObjective-Cでランタイムプログラミングを行おうとしています。これを行うために、resolveClassMethodメソッドをオーバーライドします。
残念ながら、ARCがアクティブなときにclangでコンパイルエラーが発生します:
エラー:セレクター'動的'の既知のクラスメソッドがありません
エラーの代わりに警告を除いて、ARCなしでgccまたはclangを使用すると(-fno-objc-arcオプションが渡されます)、すべてが正常に機能します。
ARCは、戻り値を使用してメモリを管理する方法を理解するために呼び出されるメソッドの名前を知る必要があることを認識しています(メソッド名の規則に従います)。しかし、直接メソッド呼び出しの代わりに醜いperformSelector呼び出しなしでこの問題を解決するにはどうすればよいですか?
これが私のコードです:
Test.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
Test.h
#import <Cocoa/Cocoa.h>
@interface Test : NSObject <NSObject> {
NSString *_name;
}
- (NSString*)name;
@end
main.m
#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:警告:クラスメソッド'+ dynamic'が見つかりません(戻り型のデフォルトは' 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でClang
コンパイル結果
main.m:13:36:エラー:セレクター「動的」の既知のクラスメソッドがありません
NSLog(@"How are you , %@", [Test dynamic]);
PS:私の目標は、ARCをアクティブにしてこのコードをコンパイルすることなので、メモリ管理については今のところ気にしませんでした。