Я пытаюсь решить головоломку.
__strong
является значением по умолчанию для всех сохраняемых указателей объектов Objective-C, таких как NSObject, NSString и т. д. Это сильная ссылка. ARC уравновешивает это с помощью a -release
в конце области видимости.
__unsafe_unretained
равно старому. Он используется для слабого указателя без сохранения сохраняемого объекта.
__weak
похоже, __unsafe_unretained
за исключением того, что это слабая ссылка с автоматическим обнулением, означающая, что указатель будет установлен в ноль, как только объект, на который ссылается, будет освобожден. Это устраняет опасность зависших указателей и ошибок EXC_BAD_ACCESS.
Но что именно __autoreleasing
хорошо? Мне сложно найти практические примеры, когда мне нужно использовать этот квалификатор. Я считаю, что это только для функций и методов, которые ожидают указатель-указатель, например:
- (BOOL)save:(NSError**);
или
NSError *error = nil;
[database save:&error];
который под ARC должен быть объявлен следующим образом:
- (BOOL)save:(NSError* __autoreleasing *);
Но это слишком расплывчато, и я хотел бы полностью понять, почему . Во фрагментах кода, которые я нахожу, __autoreleasing помещается между двумя звездами, что мне кажется странным. Типом является NSError**
(указатель-указатель на NSError), так почему же ставить __autoreleasing
между звездами, а не просто перед ними NSError**
?
Кроме того, могут быть и другие ситуации, на которые я должен положиться __autoreleasing
.
источник
Ответы:
Ты прав. Как объясняется в официальной документации:
Все это очень хорошо объясняется в руководстве по переходу ARC .
В вашем примере NSError объявление
__strong
неявно означает :Преобразуется в:
Когда вы вызываете свой
save
метод:Затем компилятору нужно будет создать временную переменную, установленную в
__autoreleasing
. Так:Преобразуется в:
Вы можете избежать этого
__autoreleasing
, напрямую объявив объект ошибки как .источник
__autoreleasing
используется только для аргументов, переданных по ссылке. Это особый случай, поскольку у вас есть указатель на указатель объекта. Это не относится к таким вещам, как удобные конструкторы, поскольку они возвращают только указатель на объект, а ARC обрабатывает его автоматически.Следуя ответу Макмаде и последующему вопросу Гордого члена в комментариях, (также разместил бы это как комментарий, но он превышает максимальное количество символов):
Вот почему квалификатор переменной __autoreleasing помещен между двумя звездами.
Чтобы предисловие, правильный синтаксис для объявления указателя на объект с квалификатором:
Компилятор простит это:
но это неверно. См. Руководство по переходу Apple ARC (прочтите раздел, который начинается с «Правильно декорировать переменные ...»).
Чтобы обратиться к рассматриваемому вопросу: двойной указатель не может иметь квалификатор управления памятью ARC, потому что указатель, указывающий на адрес памяти, является указателем на примитивный тип, а не указателем на объект. Однако, когда вы объявляете двойной указатель, ARC действительно хочет знать, каковы правила управления памятью для второго указателя. Вот почему переменные с двойным указателем указываются как:
Таким образом, в случае аргумента метода, который является двойным указателем NSError, тип данных объявляется как:
который на английском языке говорит «указатель на указатель объекта __autoreleasing NSError».
источник
В окончательной спецификации ARC говорится, что
Так, например, код
фактически преобразуется в
... поэтому он работает, когда у вас есть параметр
NSError* __autoreleasing * errorPointer
, вызываемый метод затем назначит ошибку,*errorPointer
и вышеуказанная семантика сработает.Вы можете использовать
__autoreleasing
в другом контексте, чтобы принудительно поместить объект ARC в пул автозапуска, но это не очень полезно, поскольку ARC, кажется, использует пул автозапуска только при возврате метода и уже обрабатывает это автоматически.источник