Почему мигратор ARC сообщает, что -setArgument: NSInvocation небезопасен, если только аргумент - __unsafe_unrehibited?

Я переносил блок кода на автоматический подсчет ссылок (ARC), и мигратор ARC выдал ошибку

NSInvocation's setArgument небезопасно использовать с объектом с право собственности, отличное от __unsafe_unrehibited

в коде, где я выделил объект, используя что-то вроде

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

, а затем установил его как аргумент NSInvocation, используя

[theInvocation setArgument:&testNumber1 atIndex:2];

Почему это мешает вам сделать это? Кажется столь же плохим использовать объекты __ unsafe_unrehibited в качестве аргументов.Например, следующий код вызывает сбой в 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_unrehibited tempNumber не сохраняет его после исходный указатель устанавливается на nil (имитирует случай, когда вызов используется после того, как исходная ссылка на аргумент исчезла). Если строка -retainArguments раскомментирована (в результате чего NSInvocation удерживает аргумент), этот код не аварийно завершается.

Тот же самый сбой происходит, если я использую testNumber1 непосредственно в качестве аргумента для -setArgument: , и он также исправляется, если вы используете -retainArguments . Почему же тогда мигратор ARC говорит, что использование строго удерживаемого указателя в качестве аргумента NSInvocation -setArgument: небезопасно, если вы не используете что-то, что является __ unsafe_unreolated ?

34
задан Brad Larson 29 December 2011 в 19:46
поделиться