Як використовувати ненульові та зведені ключові слова Objective-C у блоковому методі API


105

Розглянемо наступний метод

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

але ми також отримуємо це попередження:

Вказівник відсутній в специфікаторі типу зведеності на нуль (__nonnull або __nullable)

Він відноситься до третього параметра (блок один).

Документація не поширюється з прикладами , як вказати допустимість порожніх параметрів блоку. У ньому йдеться дослівно

Ви можете використовувати форми, що не підкреслюються, зведені до нуля та не мають значення відразу після відкритої дужки, якщо тип є простим об’єктом чи покажчиком блоку.

Я намагався без жодної удачі поставити одне з двох ключових слів для блоку (у будь-яку позицію). Також випробували варіанти підкреслення ( __nonnullі __nullable).

Тому моє запитання: як я можу вказати семантичну нульовість для параметрів блоку?

Відповіді:


128

Це, здається, працює

- (void)methodWithArg:(nonnull NSString *)arg1 
  andArg:(nullable NSString *)arg2 completionHandler:(nullable void (^)
  (NSArray * _Nullable results, NSError * _Nonnull error))completionHandler

Вам потрібно вказати нульовість і для блоку, і для його параметрів ...

РЕДАКТУВАННЯ: Для отримання додаткової інформації див. Блог Swift


Як це працює з NSError **типом? Я не можу зробити компілятора щасливим.
duhanebel

3
Згідно з швидким блогом: The particular type NSError ** is so often used to return errors via method parameters that it is always assumed to be a nullable pointer to a nullable NSError reference. developer.apple.com/swift/blog/?id=25
користувач1687195

@duhanebel Відповідь дається в stackoverflow.com/questions/33198597 / ... : (NSError * _Nullable * _Nullable) помилка
Elise ван Looij

33

Згідно з Apple Blog ("Nullability and 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відразу після відкритих дужок, якщо тип є простим об’єктом або покажчиком блоку.

перевірте більше в "Зменшення і об'єктивності-С"

Для безпеки є кілька винятків із цього правила:

  • typedefтипи, як правило, не мають властивої нульовості - вони можуть бути легко нульовими або нерегульованими залежно від контексту. Тому typedefтипи не передбачаються nonnullнавіть у регіонах, що перевіряються.
  • Більш складні типи вказівників, як-от, id *повинні бути явно помічені. Наприклад, щоб вказати ненульований покажчик на посилання на об'єкт, що зводиться до нуля, використовуйте _Nullable id * _Nonnull.
  • Конкретний тип NSError **настільки часто використовується для повернення помилок через параметри методу, що завжди вважається нульовим покажчиком на нульову NSErrorпосилання.

_Nullable id * _NonnullМожна спитати, id _Nullable * _Nonnullкраще розуміння.

_Nonnullі _Nullableслід використовувати після вказівника або id(Apple робить у прикладі кодуAAPLListItem * _Nullable )


Для слабкої властивості застосовано _Nullable.
Dongjin Suh

3

Ви також можете зробити так:

- (id __nullable)methodWithArg:(NSString * __nullable)arg1
                        andArg:(NSString * __nonnull)arg2
             completionHandler:(void (^ __nonnull)(NSArray * __nonnull results, NSError * __nullable error))completionHandler;

Тільки залежить, який синтаксис вам більше подобається.


2

Для визначення завершень у файлі заголовка я це зробив

typedef void (^PublicEventsHandler) (BOOL success, NSArray * _Nullable publicEvents);

Звичайно, я згоден з прийнятою відповіддю.


0

З блогу розробників яблук : Core: _Nullable та _Nonnull

ви можете використовувати форми, які не підкреслюються, зведені до нуля і не мають значення відразу після відкритої дужки , якщо тип є простим об’єктом або покажчиком блоку.

Не підкреслені форми є кращими, ніж підкреслені, але вам все одно потрібно застосувати їх до кожного типу у своєму заголовку .


Так, але ті, хто не підкреслює (приємніші), не працюють у блокових деклараціях
Пол Бруно,

-2

Ось що я використав для випадку NSError **:

-(BOOL) something:(int)number withError:(NSError *__autoreleasing  __nullable * __nullable)error;

1
Як сказав Apple , для цього NSError **вам не потрібно вказувати його нульовість.
Світанок
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.