Нужно больше объяснений по использованию autoreleasing

Я отчаянно пытаюсь понять использование __autoreleasing ключевое слово Objective-C. Я внимательно прочитал ответы на следующие вопросы:

в каких ситуациях нам нужно написать квалификатор владения _ _ autoreleasing под ARC?

использование _ _ autoreleasing в Примере фрагмента кода

NSError и __autoreleasing

и несмотря на то, что теперь я понимаю больше, я все еще не могу главное-цель. Зачем это делать? Позвольте объяснить, что именно меня смущает. Рассмотрим код:

@interface MyError : NSError

@end

@implementation MyError

- (void)dealloc
{
   NSLog(@"My error dealloc");
}

@end

@interface ErrorHandler : NSObject

- (void)handleError:(MyError* __strong*)error;

@end

@implementation ErrorHandler

- (void)handleError:(MyError* __strong*)error
{
   *error = [[MyError alloc] initWithDomain:@"Blabla" code:100500 userInfo:@{

                                                                          NSLocalizedDescriptionKey : @"TestDescription"


                                                                          }];
 }

 @end

 - (void)test
{
   MyError *error = nil;

   ErrorHandler *handler = [ErrorHandler new];

   [handler handleError:&error];

   NSLog(@"Localized description %@", error.localizedDescription);
}

я написал этот код, чтобы увидеть, что произойдет, если я не использую __autoreleasing. Как видите handleError метод принимает ссылку на ссылку, которая явно объявлены как __strong. И ничего не происходит. Все в порядке. Я могу получить информацию от MyError объект, и он был успешно освобожден, я вижу это. Если я положу __autoreleasing вместо __strong ничего изменения. Так зачем использовать __autoreleasing если это ничего не меняет? Вот чего я не понимаю. Кто-нибудь может показать мне, чего мне не хватает? Спасибо всем

1 ответов


я думаю, что ответ tl; dr заключается в том, что, объявив аргумент как __autoreleasing вы также можете передать указатель на слабую ссылку, если вы хотите.

представьте, что ваш метод выглядит так:

-(void) handleError: (NSError* __strong *) error
{
    NSError* myError = [[NSError alloc] init];
    *error = myError; 
}

компилятор думает, что *error является сильным, поэтому, когда он выполняет задание, вы получаете +1 сохранить количество. После того, как компилятор был над кодом, он выглядит следующим образом:

-(void) handleError: (NSError* __strong *) error
{
    NSError* myError = [[NSError alloc] init];
    *error = [myError retain]; 
    [myError release];
}

так что если вы называете это так:

NSError* error; // strong reference
[self handleError: &error];
это отлично, потому что компилятор правильно поместит выпуск в конце области. Если вы сделаете это, хотя:
NSError* __weak error; // weak reference
[self handleError: &error];

вероятно, он не будет компилироваться, но если это так, потому что компилятор считает ссылку слабой (она не может видеть сильное назначение в handleError:), оно не положит в отпуск и предмет протекет.

если вы определяете метод следующим образом:

-(void) handleError: (NSError* __weak *) error
{
    NSError* myError = [[NSError alloc] init];
    *error = myError; 
}

компилятор добавляет код, чтобы он выглядел так это:

-(void) handleError: (NSError* __weak *) error
{
    NSError* myError = [[NSError alloc] init];
    *error = myError; 
    [myError release];
}

это еще хуже, потому что задание *error дает +0 сохранить счет, что означает, что, как только myError выходит за рамки, т. е. когда метод возвращается, объект, на который он указывает, освобождается.

если вы сделаете это:

-(void) handleError: (NSError* __autoreleasing *) error
{
    NSError* myError = [[NSError alloc] init];
    *error = myError; 
}

компилятор делает это:

-(void) handleError: (NSError* __autoreleasing *) error
{
    NSError* myError = [[NSError alloc] init];
    *error = [[myError retain] autorelease]; 
    [myError release];
}

что совпадает с предыдущим случаем, за исключением того, что возвращаемый объект находится в пуле autorelease в конце метода, поэтому он не получит освободившему. Таким образом, вы можете объявить error в вызывающем абоненте как сильный или слабый, и компилятор имеет возможность сделать что-то разумное с возвращаемой ссылкой.

по крайней мере, я думаю, что это проблема.