ARC и мостовой состав

166

С АРК, я больше не могу бросить CGColorRefв id. Я узнал, что мне нужно сделать актерский состав. В соответствии с Clang Docs :

Приведение с мостом - это приведение в стиле C, снабженное одним из трех ключевых слов:

(__bridge T) opпереводит операнд в тип назначения T. Если T это указатель типа сохраняемого объекта, то он opдолжен иметь указатель типа без возможности сохранения. Если Tэто тип указателя с сохранением, то у op должен быть тип указателя с сохранением объекта. В противном случае актерский состав плохо сформирован. Передача права собственности не производится, и ARC не вводит операции по сохранению.

(__bridge_retained T) opпреобразует операнд, который должен иметь тип указателя сохраняемого объекта, в тип назначения, который должен быть типом указателя без возможности сохранения. ARC сохраняет значение при условии обычной оптимизации локальных значений, и получатель отвечает за балансирование этого +1.

(__bridge_transfer T) opпреобразует операнд, который должен иметь тип указателя без возможности сохранения, в тип назначения, который должен быть типом указателя сохраняемого объекта. ARC выпустит значение в конце полного выражения при условии обычной оптимизации локальных значений.

Эти приведения необходимы для передачи объектов в ARC-контроль и обратно; см. обоснование в разделе о преобразовании указателей сохраняемых объектов.

Использование __bridge_retainedили __bridge_transferприведение только для того, чтобы убедить ARC испустить несбалансированное удержание или освобождение, соответственно, является плохой формой.

В каких ситуациях я бы использовал каждый?

Например, CAGradientLayerимеет colorsсвойство, которое принимает массив CGColorRefs. Я думаю, что я должен использовать __brigeздесь, но точно, почему я должен (или не должен) неясно.

Morrowless
источник
17
Вы уже смотрели сессию WWDC 2011 323? Это объясняет ARC гораздо лучше, чем я мог здесь. Он охватывает все детали от начала до конца. Это сессия для каждого разработчика Mac / iOS.
rbrown
Это может также помочь: stackoverflow.com/questions/14352494/…
Эван Меллор
Ссылка на WWDC сессию, не была тривиальной найти: developer.apple.com/videos/play/wwdc2011/323 - Соответствующий бит в 23:15
Daniel

Ответы:

215

Я согласен, что описание сбивает с толку. Так как я только что понял их, я постараюсь подвести итог:

  • (__bridge_transfer <NSType>) opили, в качестве альтернативы CFBridgingRelease(op), используется, чтобы использовать счет удержания CFTypeRefпри передаче его в ARC. Это также может быть представленоid someObj = (__bridge <NSType>) op; CFRelease(op);

  • (__bridge_retained <CFType>) opили, в качестве альтернативы CFBridgingRetain(op), используется для NSObjectпередачи на CF-землю, в то же время давая ему +1 счет удержания. Вы должны обращаться с CFTypeRefсозданным вами способом так же, как с результатом CFStringCreateCopy(). Это также может быть представленоCFRetain((__bridge CFType)op); CFTypeRef someTypeRef = (__bridge CFType)op;

  • __bridgeпросто бросает между указателем-землей и объектом-землей Objective-C. Если у вас нет желания использовать приведенные выше преобразования, используйте этот.

Может быть, это полезно. Сам я предпочитаю CFBridging…макросы немного более простым броскам.

monkeydom
источник
Увеличивается ли количество сохраняемых объектов на дуги на 1 при использовании __bridge_transfer? В противном случае может показаться, что в тот момент, когда CFRelease () вызывается, объект исчезает и ничего не указывает. Точно так же, когда вы используете __bridge_retain, уменьшает ли ARC счет сохранения операции на 1? Иначе кажется, что объект никогда не будет выпущен должным образом.
Тони
2
Оказавшись в стране ARC, вы больше не думаете о сохранении счета, а только о сильных и слабых ссылках.
Монкейдом
4
Да, если вы находитесь только на дуговой земле, сильного / слабого будет достаточно, однако, когда вы перемещаете объекты между дуговой и не-дуговой средами, вам все равно придется задуматься о последствиях сохранения количества под капотом
Tony
3
На самом деле, нет. Вы должны думать только о том, чтобы войти и покинуть землю АРК. И это довольно приятное восприятие авто-релиза. (достаточно интересно: ARC исправляет общий шаблон, такой как извлечение объекта из словаря, затем удаление его перед использованием и т. д.)
monkeydom
3
использование инструмента «Анализатор» (shift + command + B) может помочь в разрешении таких сомнений, поскольку он скажет вам на естественном языке, если в текущем коде происходит утечка памяти. Если это произойдет, вы, вероятно, используете удерживающий бросок, в то время как вы должны использовать не удерживающий бросок. если анализатор не предупредит вас ни о чем в этих строках кода, вы, вероятно, преуспеваете с текущим кодом
Фабио Наподано
55

В документации iOS я нашел другое объяснение, которое, по-моему, легче понять:

  • __bridge передает указатель между Objective-C и Core Foundation без передачи права собственности.

  • __bridge_retained (CFBridgingRetain)Направляет указатель Objective C на указатель Core Foundation, а также передает право собственности на вас.

    Вы несете ответственность за вызов CFRelease или связанной функции, чтобы отказаться от владения объектом.

  • __bridge_transfer (CFBridgingRelease)перемещает не-Objective-C указатель на Objective-C, а также передает владение ARC.

    ARC отвечает за отказ от владения объектом.

Источник: бесплатные мостовые типы

gregschlom
источник
33

Как продолжение, в этом конкретном случае, если вы работаете на iOS, Apple рекомендует использовать UIColor и его -CGColorметод для возврата CGColorRef в colorsNSArray. В примечаниях к выпуску « Переход к ARC» в разделе «Компилятор обрабатывает объекты CF, возвращенные из методов какао», указано, что использование метода, подобного -CGColorвозвращающему объект Core Foundation, будет автоматически обрабатываться компилятором должным образом.

Таким образом, они предлагают использовать код, подобный следующему:

CAGradientLayer *gradientLayer = (CAGradientLayer *)[self layer];
gradientLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor darkGrayColor] CGColor],
                                                 (id)[[UIColor lightGrayColor] CGColor], nil];

Обратите внимание, что на данный момент в примере кода Apple отсутствует приведенное выше приведение (id), которое все еще необходимо, чтобы избежать ошибки компилятора.

Брэд Ларсон
источник
Как правило, вы можете обойтись, просто приведя первый из объектов (id) вместо всех, если хотите.
Филипп Сабурин
1
Этот вопрос задает вопрос о трансляции с ARC, когда вставленный вами код является недопустимым.
Джои Хагедорн
11
@JoeyHagedorn - Возможно, вы пропустили мою ссылку на документацию ARC в первом предложении моего ответа, но это не только допустимо в ARC, это рекомендуемый подход для предоставления ссылок CGColorRef в NSArrays из этих методов преобразования UIColor. Я и многие другие использую этот точный код в приложениях с поддержкой ARC. Непосредственное приведение к (id) из метода, который возвращает объект Core Foundation, автоматически связывает этот объект с ARC.
Брэд Ларсон