为什么ARC迁移器说NSInvocation的-setArgument:不安全,除非参数是__unsafe_unretained? [英] Why does the ARC migrator say that NSInvocation's -setArgument: is not safe unless the argument is __unsafe_unretained?

查看:646
本文介绍了为什么ARC迁移器说NSInvocation的-setArgument:不安全,除非参数是__unsafe_unretained?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将代码块迁移到自动引用计数(ARC),并让ARC迁移器引发错误

I was migrating a block of code to automatic reference counting (ARC), and had the ARC migrator throw the error


NSInvocation的setArgument不能安全地使用
所有权而不是__unsafe_unretained的对象

NSInvocation's setArgument is not safe to be used with an object with ownership other than __unsafe_unretained

在我已分配对象的代码上使用类似

on code where I had allocated an object using something like

NSDecimalNumber *testNumber1 = [[NSDecimalNumber alloc] initWithString:@"1.0"];

然后将其设置为NSInvocation参数

then set it as an NSInvocation argument using

[theInvocation setArgument:&testNumber1 atIndex:2];

为什么会阻止你这样做?使用 __ unsafe_unretained 对象作为参数看起来也很糟糕。例如,以下代码导致ARC下的崩溃:

Why is it preventing you from doing this? It seems just as bad to use __unsafe_unretained objects as arguments. For example, the following code causes a crash under 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;

在原始指针设置为之后,临时 __ unsafe_unretained tempNumber nil (模拟在对参数的原始引用消失后使用调用的情况)。如果 -retainArguments 行未注释(导致NSInvocation保存参数),则此代码不会崩溃。

due to the overrelease of testNumber1, because the temporary __unsafe_unretained tempNumber variable is not holding on to it after the original pointer is set to nil (simulating a case where the invocation is used after the original reference to an argument has gone away). If the -retainArguments line is uncommented (causing the NSInvocation to hold on to the argument), this code does not crash.

如果我直接使用 testNumber1 作为 -setArgument:的参数,如果使用 -retainArguments ,则固定。那么,为什么ARC迁移者说使用强持有的指针作为NSInvocation的 -setArgument:的参数是不安全的,除非你使用 __ unsafe_unretained

The exact same crash happens if I use testNumber1 directly as an argument to -setArgument:, and it's also fixed if you use -retainArguments. Why, then, does the ARC migrator say that using a strongly held pointer as an argument to NSInvocation's -setArgument: is unsafe, unless you use something that is __unsafe_unretained?

推荐答案

这是一个完整的猜测,但是它可能与参数传递的参考作为 void *

This is a complete guess, but might it be something to do with the argument being passed in by reference as a void*?

在你提到的情况下,这并不是一个问题,调用,例如。 getArgument:atIndex:那么编译器不知道返回的参数是否需要保留。

In the case you've mentioned, this doesn't really seem a problem, but if you were to call, eg. getArgument:atIndex: then the compiler wouldn't have any way of knowing whether the returned argument needed to be retained.

From NSInvocation.h:

From NSInvocation.h:

- (void)getArgument:(void *)argumentLocation atIndex:(NSInteger)idx;
- (void)setArgument:(void *)argumentLocation atIndex:(NSInteger)idx;

由于编译器不知道方法是否通过引用返回声明具有相同的类型和属性),也许迁移者(明智地)谨慎,并告诉你避免空指针到强指针?

Given that the compiler doesn't know whether the method will return by reference or not (these two method declarations have identical types and attributes), perhaps the migrator is being (sensibly) cautious and telling you to avoid void pointers to strong pointers?

例如:

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

这篇关于为什么ARC迁移器说NSInvocation的-setArgument:不安全,除非参数是__unsafe_unretained?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆