以下のようなMyClassという独自クラスがあったとします。
// MyClass.h
@interface MyClass : NSObject
- (void)printMessage:(NSString*)text;
@end
// MyClass.m
@implementation MyClass
- (id)init
{
if ((self = [super init])) {
NSLog(@"init: %@",self);
}
return self;
}
- (void)printMessage:(NSString*)text
{
NSLog(@"Message: %@",text);
}
@end
文字列からインスタンス生成
まず、このクラス名の文字列を元に、インスタンスを生成してみます。
// 非ARCの場合
Class c = NSClassFromString(@"MyClass");
id obj = nil;
if (c)
obj = [[[c alloc] init] autorelease];
}
// ARCの場合
Class c = NSClassFromString(@"MyClass");
id obj = nil;
if (c) {
obj = [[c alloc] init];
}
なぜ、わざわざ非ARCとARCのコードを書いたのかは後で解説します。文字列からメソッド呼び出し
MyClassのprintMessage:メソッドを呼び出してみます。NSObjectクラスのperformSelectorを使用しますが、printMessage:は1つのオブジェクトを受け取るメソッドなのでperformSelector:withObject:を使用します。
// 非ARCの場合
SEL method = NSSelectorFromString(@"printMessage:"); // :を忘れずに!
if ([obj respondsToSelector:method]) {
[obj performSelector:method withObject:@"hello!"];
}
// ARCの場合
SEL method = NSSelectorFromString(@"printMessage:"); // :を忘れずに!
if ([obj respondsToSelector:method]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[obj performSelector:method withObject:@"hello!"];
#pragma clang diagnostic pop
}
さてここで、非ARCとARCのコードに違いが出てきました。
performSelector:withObject:メソッドはid型オブジェクトを返す事ができます。
ただしprintMessage:の返り値はvoidで、何も返さないはずです。
文字列から生成したメソッド名では静的にメソッドを特定できないので、これらの事がARCプロジェクトの場合にコンパイラが理解できず、"performSelector may cause a leak because its selector is unknown"というワーニングを吐き出します。
何も値を返さないなら、このワーニングを無視してしまって構わないのですが、ワーニングを抑制したい場合は、先の一連の#pragma文を使用します。
または、ビルドセッティングのOther Warning Flagsに-Wno-arc-performSelector-leaksを設定することで、プロジェクト全体で同様の効果が得られますが、場所によってはこのワーニングがバグの発見に寄与する可能性もありますので、あまりお勧めは出来ません。
0 件のコメント:
コメントを投稿