ARC и мостовой литой
С ARC я больше не могу отбрасывать CGColorRef
до id
. Я узнал, что мне нужно сделать мостовой бросок. Согласно clang docs:
A bridged cast - это стиль C-стиля, аннотированный одним из трех ключевых слов:
(__bridge T) op
переводит операнд в тип назначения T
. Если T
является сохраняемым типом указателя объекта, тогда op
должен иметь не сохраняемый тип указателя. Если T
- не сохраняемый тип указателя, то op должен иметь тип сохраняемого типа объекта. В противном случае бросок плохо сформирован. Передача права собственности отсутствует, и ARC не вставляет сохранить операции.
(__bridge_retained T) op
выдает операнд, который должен иметь тип сохраняемого типа объекта, к типу назначения, который должен быть не сохраняемый тип указателя. ARC сохраняет значение, при условии, что обычная оптимизация по локальным значениям, а получатель отвечает для балансировки, что +1.
(__bridge_transfer T) op
выдает операнд, который должен иметь не сохраняемый тип указателя, к типу назначения, который должен быть сохраняемый тип указателя объекта. ARC выпустит значение в конце включения полного выражения, при условии обычной оптимизации по локальным значениям.
Эти отбрасывания необходимы для переноса объектов в и из Контроль ARC; см. обоснование в разделе о конверсии сохраняемые указатели объектов.
Использование a __bridge_retained
или __bridge_transfer
для чистоты, чтобы убедить ARC для испускания неуравновешенного удержания или освобождения, соответственно, является плохим форма.
В каких ситуациях я бы использовал каждый?
Например, CAGradientLayer
имеет свойство colors
, которое принимает массив CGColorRef
s. Я предполагаю, что я должен использовать __brige
здесь, но именно поэтому я должен (или не должен) неясно.
Ответы
Ответ 1
Я согласен с тем, что описание сбивает с толку. Поскольку я только что понял их, я попытаюсь подвести итог:
-
(__bridge_transfer <NSType>) op
или, альтернативно, CFBridgingRelease(op)
используется для использования счетчика сохранения CFTypeRef
при передаче его в ARC. Это также может быть представлено id someObj = (__bridge <NSType>) op; CFRelease(op);
-
(__bridge_retained <CFType>) op
или, альтернативно, CFBridgingRetain(op)
используется, чтобы передать NSObject
на CF-land, давая ему счет сохранения +1. Вы должны обрабатывать CFTypeRef
, вы создаете этот путь так же, как вы бы обрабатывали результат CFStringCreateCopy()
. Это также может быть представлено CFRetain((__bridge CFType)op); CFTypeRef someTypeRef = (__bridge CFType)op;
-
__bridge
просто бросает между областью указателя и объектной землей Objective-C. Если у вас нет желания использовать приведенные выше преобразования, используйте этот.
Возможно, это полезно. Сам я предпочитаю макросы CFBridging…
совсем немного по сравнению с обычными трансляциями.
Ответ 2
В документации iOS я нашел другое объяснение, которое, как мне кажется, легче понять:
-
__bridge
переносит указатель между Objective-C и Core Foundation без передачи права собственности.
-
__bridge_retained (CFBridgingRetain)
добавляет указатель Objective-C указателя Core Foundation, а также передает вам право собственности.
Вы отвечаете за вызов CFRelease или связанной функции для отказа от владения объектом.
-
__bridge_transfer (CFBridgingRelease)
перемещает указатель не Objective-C на Objective-C, а также передает право собственности на ARC.
ARC отвечает за отказ от владения объектом.
Источник: Неограниченные мостовые типы
Ответ 3
В следующем конкретном случае, если вы работаете в iOS, Apple рекомендует использовать UIColor и его метод -CGColor
, чтобы вернуть CGColorRef в colors
NSArray. В разделе Переход к заметкам о выпуске ARC в разделе "Компилятор обрабатывает CF-объекты, возвращенные из методов Cocoa", указывается, что использование метод типа -CGColor
, который возвращает объект Core Foundation, автоматически обрабатывается компилятором.
Таким образом, они предлагают использовать следующий код:
CAGradientLayer *gradientLayer = (CAGradientLayer *)[self layer];
gradientLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor darkGrayColor] CGColor],
(id)[[UIColor lightGrayColor] CGColor], nil];
Обратите внимание, что на данный момент в примере кода Apple отсутствует листинг (id), который у меня выше, что по-прежнему необходимо для предотвращения ошибки компилятора.