いいえ。
答えが「はい」の場合、NSInvocation
ブロックをコピーするのに十分スマートな場合、次のようにする必要があります。
for (/*every arguments*/) {
if (/*arg is object. i.e. @encode(arg) is '@'*/) {
if ([arg isKindOfClss:[NSBlock class]]) {
arg = [arg copy]; // copy block
} else {
[arg retain];
}
}
}
問題はarg
、ブロックのコピー中に が変更されることです。これは、呼び出しretainArguments
が の引数を変更する可能性があるため、発生しないはずNSInvocation
です。これは、すでに行われている多くの仮定を破ります。(つまり、から取得するNSInvocation
引数は、を作成するために使用される引数と同じである必要がありますNSInvocation
)
アップデート
答えを一致させるためにテストを行ったところNOですが、私の前のポイントは間違っていました...
@interface Test : NSObject
@end
@implementation Test
- (void)testMethodWithBlock:(void (^)(void))block obj:(id)obj cstr:(const char *)cstr {
NSLog(@"%p %p %p %@", block, obj, cstr, [block class]);
}
@end
@implementation testTests
- (void)test1 {
__block int dummy;
Test *t = [[Test alloc] init];
NSMethodSignature *ms = [t methodSignatureForSelector:@selector(testMethodWithBlock:obj:cstr:)];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:ms];
void (^block)(void) = ^ {
dummy++; // stop this become global block
};
id obj = @"object";
char *cstr = malloc(5);
strcpy(cstr, "cstr");
NSLog(@"%@", [ms debugDescription]);
NSLog(@"%p %p %p %@", block, obj, cstr, [block class]);
[invocation setSelector:@selector(testMethodWithBlock:obj:cstr:)];
[invocation setArgument:&block atIndex:2];
[invocation setArgument:&obj atIndex:3];
[invocation setArgument:&cstr atIndex:4];
[invocation invokeWithTarget:t];
[invocation retainArguments];
[invocation invokeWithTarget:t];
free(cstr);
}
@end
出力、ARC 無効 (およびクラッシュ):
2013-04-18 19:49:27.616 test[94555:c07] 0xbfffe120 0x70d2254 0x7167980 __NSStackBlock__
2013-04-18 19:49:27.617 test[94555:c07] 0xbfffe120 0x70d2254 0x7167980 __NSStackBlock__
2013-04-18 19:49:27.618 test[94555:c07] 0xbfffe120 0x70d2254 0x736a810 __NSStackBlock__
ARC 有効:
2013-04-18 19:51:03.979 test[95323:c07] 0x7101e10 0x70d2268 0x7101aa0 __NSMallocBlock__
2013-04-18 19:51:03.979 test[95323:c07] 0x7101e10 0x70d2268 0x7101aa0 __NSMallocBlock__
2013-04-18 19:51:03.980 test[95323:c07] 0x7101e10 0x70d2268 0xe0c1310 __NSMallocBlock__
ご覧のとおり、c 文字列はretainArguments
ブロックではなくコピーされます。しかし、ARC が有効になっていると、ARC がある時点でコピーされたので、問題は解決するはずです。