Clang обнуляемость предупреждения и как к ним подойти

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

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

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

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

2 ответа

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

- (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;
}

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

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

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

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

Во-первых, вы должны включить 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; })

Здесь вы можете увидеть хаки __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];
  }
}

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

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