我正在将一段代码迁移到自动引用计数 (ARC),并让 ARC 迁移器抛出错误
NSInvocation's setArgument is not safe to be used with an object with ownership other than __unsafe_unretained
在我使用类似方法分配对象的代码上
NSDecimalNumber *testNumber1 = [[NSDecimalNumber alloc] initWithString:@"1.0"];
然后使用 将其设置为 NSInvocation 参数
[theInvocation setArgument:&testNumber1 atIndex:2];
为什么它会阻止您这样做?使用 __unsafe_unretained
对象作为参数似乎同样糟糕。例如,以下代码在 ARC 下会导致崩溃:
NSDecimalNumber *testNumber1 = [[NSDecimalNumber alloc] initWithString:@"1.0"];
NSMutableArray *testArray = [[NSMutableArray alloc] init];
__unsafe_unretained NSDecimalNumber *tempNumber = testNumber1;
NSLog(@"Array count before invocation: %ld", [testArray count]);
// [testArray addObject:testNumber1];
SEL theSelector = @selector(addObject:);
NSMethodSignature *sig = [testArray methodSignatureForSelector:theSelector];
NSInvocation *theInvocation = [NSInvocation invocationWithMethodSignature:sig];
[theInvocation setTarget:testArray];
[theInvocation setSelector:theSelector];
[theInvocation setArgument:&tempNumber atIndex:2];
// [theInvocation retainArguments];
// Let's say we don't use this invocation until after the original pointer is gone
testNumber1 = nil;
[theInvocation invoke];
theInvocation = nil;
NSLog(@"Array count after invocation: %ld", [testArray count]);
testArray = nil;
由于 testNumber1
的过度释放,因为临时 __unsafe_unretained
tempNumber
变量在原始指针设置为nil
(模拟在对参数的原始引用消失后使用调用的情况)。如果 -retainArguments
行未注释(导致 NSInvocation 保留参数),则此代码不会崩溃。
如果我将 testNumber1
直接用作 -setArgument:
的参数,则会发生完全相同的崩溃,如果您使用 -retainArguments
,它也会得到修复>。那么,为什么 ARC 迁移器说使用强保持指针作为 NSInvocation 的 -setArgument:
的参数是不安全的,除非您使用 __unsafe_unretained
的东西?
最佳答案
这完全是猜测,但这可能与通过引用作为 void*
传递的参数有关吗?
在您提到的情况下,这似乎并不是真正的问题,但如果您要打电话,例如。 getArgument:atIndex:
那么编译器将无法知道是否需要保留返回的参数。
来自 NSInvocation.h:
- (void)getArgument:(void *)argumentLocation atIndex:(NSInteger)idx;
- (void)setArgument:(void *)argumentLocation atIndex:(NSInteger)idx;
鉴于编译器不知道该方法是否会通过引用返回(这两个方法声明具有相同的类型和属性),也许迁移者(明智地)谨慎并告诉您避免指向 strong 的 void 指针指针?
例如:
NSDecimalNumber* val;
[anInvocation getArgument:&val atIndex:2];
anInvocation = nil;
NSLog(@"%@", val); // kaboom!
__unsafe_unretained NSDecimalNumber* tempVal;
[anInvocation getArgument:&tempVal atIndex:2];
NSDecimalNumber* val = tempVal;
anInvocation = nil;
NSLog(@"%@", val); // fine
关于objective-c - 为什么 ARC 迁移器说 NSInvocation 的 -setArgument : is not safe unless the argument is __unsafe_unretained?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8672675/