gpt4 book ai didi

objective-c - 为什么 ARC 迁移器说 NSInvocation 的 -setArgument : is not safe unless the argument is __unsafe_unretained?

转载 作者:太空狗 更新时间:2023-10-30 03:08:39 25 4
gpt4 key购买 nike

我正在将一段代码迁移到自动引用计数 (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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com