Cara menggunakan kata kunci Objective-C nonnull dan nullable dalam metode API berbasis blok

105

Simak cara berikut ini

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

Dengan kata kunci baru nonnulldan nullable anotasi kita dapat memperkayanya sebagai berikut:

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

tapi kami juga mendapatkan peringatan ini:

Pointer tidak memiliki penentu jenis nullability (__nonnull atau __nullable)

Ini mengacu pada parameter ketiga (blok satu).

The dokumentasi tidak mencakup dengan contoh-contoh bagaimana menentukan nullability parameter blok. Ini menyatakan kata demi kata

Anda bisa menggunakan formulir yang tidak digarisbawahi nullable dan nonnull segera setelah kurung buka, selama tipenya adalah objek sederhana atau penunjuk blok.

Saya mencoba meletakkan salah satu dari dua kata kunci untuk blok (di posisi apa pun) tanpa hasil. Juga mencoba varian yang diawali garis bawah ( __nonnulldan __nullable).

Oleh karena itu pertanyaan saya adalah: bagaimana saya dapat menentukan semantik nullability untuk parameter blok?

albertodebortoli.dll
sumber

Jawaban:

128

Sepertinya ini berhasil

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

Anda perlu menentukan nullability baik untuk blok dan parameternya ...

EDIT: Untuk informasi selengkapnya, lihat Blog Swift

Fabio Ritrovato
sumber
Bagaimana cara kerjanya dengan NSError **tipe? Sepertinya saya tidak bisa membuat kompiler senang.
duhanebel
3
Menurut blog swift: 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
user1687195
@duhanebel Jawabannya diberikan di stackoverflow.com/questions/33198597/… : (NSError * _Nullable * _Nullable) error
Elise van Looij
33

Menurut Blog Apple ("Nullability and Objective-C") , Anda dapat menggunakan

NS_ASSUME_NONNULL_BEGINdan NS_ASSUME_NONNULL_END.

Dalam wilayah ini, semua jenis penunjuk sederhana akan dianggap sebagai nonnull. Kemudian Anda bisa menambahkan nullableobjek nullable, seperti

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
  • jika kesalahan adalah NSError **jenis, harusNSError * _Nullable * _Nullable
  • jika objek adalah id *tipe, lebih baik gunakan id _Nullable * _Nonnull, itu tergantung (mungkin Anda menginginkan _Nullable id * _Nullabletipe).
  • jika objek NSObject *bertipe, Anda perlu menambahkan anotasi setelah pointer, seperti iniNSObject * _Nullable * _Nonnull

Catatan

_Nonnulldan _Nullableharus digunakan setelah penunjuk atau id(Apple melakukannya dalam kode contoh AAPLListItem * _Nullable), tetapi bentuk yang tidak digarisbawahi nonnulldan nullabledapat digunakan setelah kurung buka.

Namun, dalam kasus umum, ada cara yang jauh lebih baik untuk menulis anotasi ini: dalam deklarasi metode Anda dapat menggunakan formulir yang tidak digarisbawahi nullabledan nonnullsegera setelah kurung buka, selama tipenya adalah objek sederhana atau penunjuk blok.

periksa lebih lanjut di "Nullability dan Objective-C"

Demi keamanan, ada beberapa pengecualian untuk aturan ini:

  • typedefjenis biasanya tidak memiliki nullability yang melekat — mereka dapat dengan mudah menjadi nullable atau non-nullable bergantung pada konteksnya. Oleh karena itu, typedefjenis tidak diasumsikan nonnull, bahkan di dalam wilayah yang diaudit.
  • Jenis penunjuk yang lebih kompleks seperti id *harus dijelaskan secara eksplisit. Misalnya, untuk menentukan pointer non-nullable ke referensi objek nullable, gunakan _Nullable id * _Nonnull.
  • Jenis tertentu NSError **begitu sering digunakan untuk mengembalikan kesalahan melalui parameter metode yang selalu dianggap sebagai penunjuk nullable ke NSErrorreferensi nullable .

Yang _Nullable id * _Nonnullbisa dibingungkan, id _Nullable * _Nonnulladalah pemahaman yang lebih baik.

_Nonnulldan _Nullableharus digunakan setelah penunjuk atau id(Apple melakukannya dalam kode contohAAPLListItem * _Nullable )

likid1412
sumber
Untuk properti lemah, _Nullable diterapkan.
Dongjin Suh
3

Anda juga bisa melakukan seperti ini:

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

Itu hanya tergantung sintaks mana yang lebih Anda sukai.

OlDor
sumber
2

Untuk menentukan penyelesaian di file header saya melakukan ini

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

Tentu saja, saya setuju dengan jawaban yang diterima.

Krishna Kumar
sumber
0

Dari blog pengembang apel : Inti: _Nullable dan _Nonnull

Anda dapat menggunakan formulir yang tidak digarisbawahi nullable dan nonnull segera setelah kurung buka , selama tipenya adalah objek sederhana atau penunjuk blok.

Formulir yang tidak digarisbawahi lebih bagus daripada yang digarisbawahi, tetapi Anda masih perlu menerapkannya ke setiap jenis di header Anda .

Parag Bafna
sumber
Ya, tetapi yang non-garis bawah (lebih bagus) tidak berfungsi dalam deklarasi blok
Paul Bruneau
-2

Inilah yang telah saya gunakan untuk kasus NSError **:

-(BOOL) something:(int)number withError:(NSError *__autoreleasing  __nullable * __nullable)error;
Kevin
sumber
1
Seperti yang dikatakan Apple , karena NSError **, Anda tidak perlu menentukan nullability-nya.
DawnSong