Мигрирах блок от код към автоматично преброяване на препратки (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 казва, че използването на силно задържан указател като аргумент за -setArgument:
на NSInvocation не е безопасно, освен ако не използвате нещо, което е __unsafe_unretained
?