Как использовать nonnull и nullable Objective-C ключевые слова в методе API на основе блоков
Рассмотрим следующий метод
- (void)methodWithArg:(NSString *)arg1 andArg:(NSString *)arg2 completionHandler:(void (^)(NSArray *results, NSError *error))completionHandler;
С помощью новых nonnull
и nullable
ключевых слов аннотации мы можем обогатить его следующим образом:
- (void)methodWithArg:(nonnull NSString *)arg1 andArg:(nullable NSString *)arg2 completionHandler:(void (^)(NSArray *results, NSError *error))completionHandler;
но мы также получаем это предупреждение:
В указателе отсутствует спецификатор типа nullability (__nonnull или __nullable)
Он ссылается на третий параметр (первый блок).
Документация не содержит примеров того, как указать допустимость параметров блока. Он утверждает дословно
Вы можете использовать незанятые формы с нулевым значением и ненулевым после открытой круглой скобки, если тип является простым объектом или указатель блока.
Я попытался поставить одно из двух ключевых слов для блока (в любой позиции) без всякой удачи. Также попытались использовать префиксные символы подчеркивания (__nonnull
и __nullable
).
Поэтому мой вопрос: как я могу указать семантику неопределенности для параметров блока?
Ответы
Ответ 1
Кажется, что это работает
- (void)methodWithArg:(nonnull NSString *)arg1
andArg:(nullable NSString *)arg2 completionHandler:(nullable void (^)
(NSArray * _Nullable results, NSError * _Nonnull error))completionHandler
Вам нужно указать значение nullability как для блока, так и его параметров...
EDIT: Для получения дополнительной информации см. Swift Blog
Ответ 2
Согласно Apple Blog ( "Nullability и Objective-C" ),
вы можете использовать
NS_ASSUME_NONNULL_BEGIN
и NS_ASSUME_NONNULL_END
.
В этих регионах любой простой тип указателя будет считаться nonnull
. Затем вы можете просто добавить nullable
для объекта с нулевым значением, который, например,
NS_ASSUME_NONNULL_BEGIN
@interface MyClass: NSObject
- (void)methodWithArg:(NSString *)arg1 andArg:(nullable NSString *)arg2 completionHandler:(void (^)(NSArray *results, NSError *error))completionHandler;
@end
NS_ASSUME_NONNULL_END
- если ошибка
NSError **
, должна быть NSError * _Nullable * _Nullable
- Если объект имеет тип
id *
, лучше использовать id _Nullable * _Nonnull
, он зависит (может быть, вы хотите тип _Nullable id * _Nullable
).
- Если тип объекта
NSObject *
, вам нужно поместить аннотацию после указателя, например NSObject * _Nullable * _Nonnull
Примечание
_Nonnull
и _Nullable
должны использоваться после указателя или id
(Apple делает в примере код AAPLListItem * _Nullable
), но без подчеркивания формы nonnull
и nullable
могут использоваться после открытой круглой скобки.
Однако, в общем случае, гораздо лучший способ написать эти аннотации: в объявлениях методов вы можете использовать не подчеркнутые формы nullable
и nonnull
сразу после открытия скобки, если тип является простым объектом или указателем блока.
проверьте больше в "Nullability и Objective-C"
Для безопасности существует несколько исключений из этого правила:
-
typedef
типы обычно не имеют присущей nullability - они могут легко быть либо нулевым, либо непустым значением в зависимости от контекста. Поэтому типы typedef
не считаются nonnull
, даже внутри проверенных регионов. - Более сложные типы указателей, такие как
id *
, должны быть явно аннотирован. Например, чтобы указать указатель, не содержащий NULL к ссылке с нулевым объектом, используйте _Nullable id * _Nonnull
. - Частный тип
NSError **
часто используется для возврата ошибок через параметры метода, которые всегда считаются нулевым указателем к нулевому значению NSError
.
_Nullable id * _Nonnull
можно смутить, id _Nullable * _Nonnull
лучше понять.
_Nonnull
и _Nullable
должны использоваться после указателя или id
(Apple делает в примере кода AAPLListItem * _Nullable
)
Ответ 3
Чтобы определить завершение в файле заголовка, я сделал это
typedef void (^PublicEventsHandler) (BOOL success, NSArray * _Nullable publicEvents);
Конечно, я согласен с принятым ответом.
Ответ 4
Вы также можете сделать следующее:
- (id __nullable)methodWithArg:(NSString * __nullable)arg1
andArg:(NSString * __nonnull)arg2
completionHandler:(void (^ __nonnull)(NSArray * __nonnull results, NSError * __nullable error))completionHandler;
Это зависит только от того, какой синтаксис вам больше нравится.
Ответ 5
Из яблока блог разработчика: Ядро: _Nullable и _Nonnull
вы можете использовать нечеркнутые формы nullable и nonnull сразу же после открытой круглой скобки, пока тип - простой объект или указатель блока.
Неподчеркнутые формы лучше, чем подчеркнутые, но Вам все равно нужно применять их к каждому типу в заголовке.
Ответ 6
Вот что я использовал для случая NSError **:
-(BOOL) something:(int)number withError:(NSError *__autoreleasing __nullable * __nullable)error;