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), который у меня выше, что по-прежнему необходимо для предотвращения ошибки компилятора.