Я переносил блок кода на автоматический подсчет ссылок (ARC), и средство миграции ARC выдало ошибку
SetArgument NSInvocation небезопасен для использования с объектом с другим владельцем, кроме __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
?