use*_*008 7 objective-c retain nsinvocation objective-c-blocks
NSInvocation-retainArguments当你不NSInvocation立即运行时,它的方法很有用,但是稍后会这样做; 它保留了对象参数,因此它们在此期间保持有效.
众所周知,应该复制块参数而不是保留.我的问题是,是否-retainArguments知道复制而不是在块类型时保留参数?文档并没有表明它确实如此,但它似乎是一件容易和明智的事情.
更新: iOS 7中的行为似乎已经发生了变化.我刚刚对此进行了测试,并且在iOS 6.1和之前,-retainArguments没有复制块类型的参数.在iOS 7及更高版本中,-retainArguments复制块类型的参数.文档-retainArguments已更新,说它复制块,但它没有说明行为何时发生变化(这对支持旧操作系统的人来说真的很危险).
不。
想象一下,如果答案是肯定的,哪里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];
}
}
}
Run Code Online (Sandbox Code Playgroud)
问题是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
Run Code Online (Sandbox Code Playgroud)
输出,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__
Run Code Online (Sandbox Code Playgroud)
启用 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__
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,c 字符串被复制,retainArguments但不是块。但启用 ARC 后,问题就会消失,因为 ARC 在某个时刻为您复制了它。
| 归档时间: |
|
| 查看次数: |
1395 次 |
| 最近记录: |