2016-03-29 2 views
0

Недавно я включил CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION в Xcode, и в моем коде Objective-C меня ошеломили предупреждения, связанные с ошибкой. Наиболее распространенным является один предупреждающий тип: Implicit conversion from nullable pointer 'TypeA * _Nullable' to non-nullable pointer type 'TypeA * _Nonnull'.Предупреждения о недействительности Clang и способы их приближения

Я начал свою попытку удалить с помощью этих предупреждений, создав локальный объект того же типа в методе, описанном здесь. https://www.mail-archive.com/xcode-users%40lists.apple.com/msg02260.html В этой статье говорится, что сначала, используя локальный, этот объект имеет атрибут неуказанный nullable, поэтому его можно использовать как законный параметр для методов, ожидающих ненулевое значение.

Но я чувствую, что это полицейский шаг и действительно не решает проблему любым полезным способом.

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

+0

В какой проблеме вы пытаетесь решить проблему? Подавление предупреждения, когда вы знаете, что объект не нуль? Или фактический процесс проверки того, что объект не равен нулю? – dan

+0

@dan Предположим, у меня есть код как следующий: 'NSMutableData * someData = [NSMutableData dataWithCapacity: d1000]; [someData appendData: [NSString stringWithFormat: @" Мне нравится выигрывать $% d ", 1000000]];'. Поскольку 'appendData:' ожидает ненулевого обходного пути, сначала нужно создать NSString * перед вызовом. В идеале я не хочу этого делать, потому что он просто добавляет лишние строки кода, которые пытаются решить проблему и не дают мне вообще никаких преимуществ. – KBancho

+0

Преимущество в том, что предупреждения больше нет. Независимо от того, стоит ли вам дополнительная строка кода, зависит от вас. Я не вижу никаких проблем с этим. – dan

ответ

1

На самом деле, я немного испортил эту тему. Я хотел улучшить ситуацию с недействительностью в несколько крупном проекте (сделать его более «быстрым»). Вот что я нашел.

Во-первых, вы должны включить CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION (-Wnullable-to-nonnull-conversion)

Во-вторых, о

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

Это плохо пахнет, и я создал макрос под названием NONNUL_CAST(). Вот пример того, как реализовать:

#define NONNUL_CAST(__var) ({ NSCAssert(__var, @"Variable is nil");\ 
    (__typeof(*(__var))* _Nonnull)__var; }) 

Здесь вы можете увидеть Hacky __typeof(*(__var))* _Nonnull)__var, но это не так уж плохо. Если __var имеет тип A* _Nullable, мы разыскиваем __var, поэтому теперь это тип A, после того, как мы сделаем ссылку снова, но _Nonnull, и получим в качестве ответа нуль __var. Конечно, мы утверждаем, что если что-то пойдет не так.

В-третьих, необходимо указать nullabilty на каждой локальной переменной, и вы должны поместить весь код в NS_ASSUME_NONNULL_BEGIN/END, как это:

NS_ASSUME_NONNULL_BEGIN 
<your_code_goes_here> 
NS_ASSUME_NONNULL_END` 

Вы положили там КАЖДЫЙ ЛИНИЯ (за исключением импорта) вашего кода, в .h и .m файлах. Это предполагает, что все ваши аргументы методов, возвращаемых типов и свойств являются ненулевыми. Если вы хотите сделать его нулевым, поместите его в нуль.

Итак, все сделано, что теперь? Вот пример типичного использования:

- (Atype*)makeAtypeWithBtype:(nullable BType*)btype { 
    Atype* _Nullable a = [btype makeAtype]; 
    if (a) { 
    // All good here. 
    return NONNUL_CAST(a); 
    } else { 
    // a appeared as nil. Some fallback is needed. 
    [self reportError]; 
    return [AtypeFactory makeDeafult]; 
    } 
} 

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

+0

Отличный ответ! У меня была такая же проблема, и я полностью забыл о разыменовании и повторной ссылке. –

0

Не каждое предупреждение имеет смысл. Иногда это недостаток в компиляторе. Например, этот код не нуждается в предупреждении.

- (nullable id)transformedValue:(nullable id)value { 
    id result = value != nil ? UIImageJPEGRepresentation(value, 1.0) : nil; 
    return result; 
} 

Мы проверяем, является ли оно нулевым! Что еще мы можем сделать? Зачем создавать дополнительный указатель?

Таким образом, мы делаем это:

- (nullable id)transformedValue:(nullable id)value { 
#pragma clang diagnostic push 
#pragma clang diagnostic ignored "-Wnullable-to-nonnull-conversion" 
    id result = value != nil ? UIImageJPEGRepresentation(value, 1.0) : nil; 
#pragma clang diagnostic pop 
    return result; 
} 

Почему это правильный ответ?

Во-первых, это нормально, если вы умнее компилятора. Вы не хотите запускать свой код, просто из-за ложного предупреждения.

Это решение определяет точное предупреждающее сообщение для подавления и подавляет его только для одной строки.

Смежные вопросы