Допустим ли __bridge_transfer для объекта NULL

Допустим, метод возвращает CFErrorRef через указатель. Эта возвращенная ошибка может быть NULL, Так было бы безопасно выполнить __bridge_transfer еще или я должен проверить NULL,

Например

CFErrorRef cfError;
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &cfError);

NSError *error = (__bridge_transfer NSError *)cfError;

Я не вижу никаких упоминаний об этом в документации и CFRelease документация конкретно гласит This value must not be NULL. https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFTypeRef/Reference/reference.html

4 ответа

Решение

Прямой ответ на вопрос: да, вы можете использовать __bridge_transfer на NULL, Но это не правильный вопрос.

Прочитайте документацию на ABAddressBookCreateWithOptions, В частности, ознакомьтесь с документацией для error:

Об ошибке, содержит информацию об ошибке. См. "Ошибки адресной книги".

Это важно.

  1. error Значение в случае успеха не задокументировано.
  2. error являющийся nil / NULL / 0 (никогда) не задокументировано.

Это не академично. Некоторые API исторически устанавливали ошибку в недопустимые значения. Представьте, что вызов установил CFError в -1, Это "верно", так как не NULL ответить означает, что вы не должны интерпретировать ошибку, но приведете мост -1 к NSError вероятно, потерпит крах.

Это означает, что вы не должны касаться cfError если ошибка не обозначена ABAddressBookCreateWithOptions возвращая NULL.

CFErrorRef cfError;
NSError *error;
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &cfError); 
if (addressBookRef == NULL) {
    error = (__bridge_transfer NSError *)cfError;
}

Вы не спрашивали об этом, но есть еще одна проблема: мосты даже не требуются, если компилятор распознает, что что-то эквивалентно 0. Например, этот код будет компилироваться без вывода сообщений (при условии _thing1 а также _thing2 являются переменными экземпляра):

- (id)bar {
    if (_thing1) return NO;
    if (_thing2) return 0;
    return NULL;
}

Это неаккуратный код, и я не должен делать это преднамеренно, но зная, что он создается чисто... это хорошая вещь, чтобы искать. Я столкнулся с ошибкой, вызванной чем-то вроде этого:

- (NSNumber *)someCalculationWithError:(NSError *)error {
   return 0; // meant to return @(0)
}

Вам не нужно проверять на NULL.

ARC - строго механизм компиляции. Когда вы используете __bridge_transfer вы просто переносите ответственность за управление памятью переменной на компилятор. Будь то cfError бывает NULL или нет во время выполнения полностью не имеет значения для компилятора.

В вашем случае ARC вставит релиз для error, но если error бывает ноль, это просто не-оп

Ошибка будет отлична от NULL, если возвращаемое значение функции равно NULL. Шаблон для этого типа функции CF заключается в том, чтобы обернуть проверку ошибок в оператор if. if (addressBookRef == NULL) { /* your error handling here */}

Вы не должны пытаться соединить что-либо, если оно не NULL. Владение объектом или, точнее, сохранение количества и ответственности за его уменьшение, не имеют значения с NULL или с нулем. Это было бы анти-паттерном. В лучшем случае это нулевая операция. Отправка сообщений на ноль с помощью Objective-C - это нормально, включая сохранение и освобождение. Неверно передавать значение NULL в CFRelease() или CGRetain().

В отличие от NSObjects, отправка сообщений объектам NULL CF не подходит. Я не знаю, что конкретно происходит при связывании, но я бы предположил, что нет, приведение объекта CF к объекту NSObject с использованием __bridge_transfer НЕ подходит.

Почему бы не попробовать и посмотреть? Приведите его к переменной в локальной области видимости метода экземпляра. Таким образом, как только метод выходит из области видимости, система должна попытаться освободить объект.

Другие вопросы по тегам