АРК і мостовий відступ


166

З АРК, я більше не можу кинути CGColorRefв id. Я дізнався, що мені потрібно виконати мост. Згідно з документами clang :

Містки кидок є C-стиль литого анотований з одним з трьох ключових слів:

(__bridge T) opвідкидає операнда до типу призначення T. Якщо T це тип вказівника з можливістю відновлення, то він opповинен мати тип невідступного вказівника. Якщо Tтип покажчика, який не можна отримати, то оп повинен мати тип вказівника, який можна отримати для об'єкта. Інакше акторський склад формується неправильно. Передача права власності не відбувається, і ARC не вставляє жодних операцій із збереженням.

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

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

Ці трансляції необхідні для передачі об'єктів в управління АРК та поза ним; див. обґрунтування в розділі про перетворення покажчиків об'єкта, що можна отримати.

Використовувати __bridge_retainedабо __bridge_transferвводити суто, щоб переконати ARC випускати незбалансоване утримування або випуск відповідно, є поганою формою.

У яких ситуаціях я б використовував кожну?

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


17
Ви ще не переглядали сесію WWDC 2011 323? Це пояснює ARC набагато краще, ніж я міг тут. Він охоплює всі деталі від початку до кінця. Це обов'язковий перегляд сеансу для кожного розробника Mac / iOS.
перекинувся

Це також може допомогти: 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)використовується для передачі NSObjectCF-land, надаючи йому номер утримання +1. Ви повинні поводитись із створеним CFTypeRefвами таким же чином, як і в результаті CFStringCreateCopy(). Це також може бути представленоCFRetain((__bridge CFType)op); CFTypeRef someTypeRef = (__bridge CFType)op;

  • __bridgeпросто кидає між покажчиком-землею та об'єктом-об'єктом-об'єктом-С. Якщо у вас немає схильності використовувати перераховані вище конверсії, використовуйте цю.

Можливо, це корисно. Сам я віддаю перевагу CFBridging…макросам трохи над рівнинами.


Чи збільшується кількість збережених об'єктів на дугу на 1 при використанні __bridge_transfer? В іншому випадку здається, що момент, коли CFRelease () називається об'єктом, пропав і нічого не вказує. Аналогічно, якщо ви використовуєте __bridge_retain, чи зменшує ARC кількість утримуваних операторів на 1? Ще здається, що об'єкт ніколи не буде належним чином випущений.
Тоні

2
Опинившись на землі ARC, ви більше не замислюєтесь про те, щоб зберегти кількість рахунків, лише про сильні та слабкі посилання.
мавповина

4
Так, якщо ви знаходитесь тільки в дуговій землі сильною / слабкою, було б достатньо, однак, коли ви переходите об'єкти між дуговими та недуговими середовищами, вам все одно доведеться задуматися про наслідки для підрахунку збереження під капотом
Тоні,

3
Не зовсім. Вам потрібно думати лише про те, щоб потрапити на землю АРК та вийти з неї. І це доволі спокійно сприймає авторелізинг. (досить цікаво: ARC виправляє загальний зразок, як вилучення об’єкта зі словника, а потім видалення його перед використанням тощо)
monkeydom

3
використання інструменту Analyzer (shift + команда + B) може допомогти у вирішенні подібних сумнівів, оскільки він скаже вам природною мовою, якщо поточний код просочується пам'яттю. Якщо це так, ви, ймовірно, використовуєте утримуючий склад, тоді як ви повинні використовувати не утримуючий склад. якщо аналізатор не попередить вас ні про що в цих рядках коду, ви, мабуть, добре справляєтесь із поточним кодом
Fabio Napodano

55

Я знайшов ще одне пояснення в документації на iOS, яке, на мою думку, простіше зрозуміти:

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

  • __bridge_retained (CFBridgingRetain)кидає вказівник Objective-C на покажчик Core Foundation, а також передає вам право власності.

    Ви несете відповідальність за виклик CFRelease або пов'язаної з ним функції, щоб відмовитись від власності на об'єкт.

  • __bridge_transfer (CFBridgingRelease)переміщує покажчик не-Objective-C на Objective-C, а також передає право власності на ARC.

    ARC несе відповідальність за відмову від права власності на об'єкт.

Джерело: Безкоштовні мостові типи


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) замість усіх, якщо хочете.
Філіп Саборін

1
Це питання задає питання про кастинг із ARC, де код, який ви вставили, не є законним.
Joey Hagedorn

11
@JoeyHagedorn - Можливо, ви пропустили моє посилання на документацію ARC в першому реченні моєї відповіді, але це не тільки те, що це дійсно в ARC, це рекомендований підхід для надання посилань на CGColorRef в NSArrays з цих методів конвертора UIColor. Я та багато інших використовую цей точний код у програмах із підтримкою ARC. Безпосереднє запрошення на (id) з методу, який повертає об'єкт Core Foundation, автоматично мостить цей об'єкт до ARC належним чином.
Бред Ларсон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.