NSInvocation
的{{1}}方法对于您不立即运行-retainArguments
但后来执行此操作非常有用;它保留了对象参数,因此它们在此期间保持有效。
众所周知,应该复制块参数而不是保留。我的问题是,NSInvocation
知道复制而不是在块类型时保留参数吗?文档并没有表明它确实如此,但这似乎是一件容易而明智的事情。
更新:iOS 7中的行为似乎已经发生了变化。我刚刚对此进行了测试,在iOS 6.1和之前,-retainArguments
没有复制块类型的参数。在iOS 7及更高版本中,-retainArguments
会复制块类型的参数。 -retainArguments
的文档已经更新,说它复制了块,但没有说明行为何时发生了变化(这对于支持旧操作系统的人来说真的很危险)。
答案 0 :(得分:4)
当然应该(虽然我自己没有测试过)。根据{{3}}:
retainArguments
如果接收方尚未这样做,请保留 目标和接收器的所有对象参数并复制它的所有参数 C字符串参数和块。
- (void)retainArguments
讨论
在调用此方法之前,argumentsRetained返回NO;之后,它返回YES。
为了提高效率,新创建的NSInvocation对象不会保留或 复制他们的论点,也不保留他们的目标,复制C. 字符串,或复制任何相关的块。你应该指导一个 NSInvocation对象如果要缓存它,则保留其参数, 因为参数可能会在调用之前释放 被调用。 NSTimer对象总是指示它们的调用 例如,保留他们的论点,因为通常会有延迟 在计时器开火之前。
答案 1 :(得分:1)
没有
图片如果答案是肯定的,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
的参数相同
<强>更新强>
刚刚做了测试以确定答案是否,但我之前的观点是不正确的......
@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会在某些时候为你复制它。