Cách sử dụng các từ khóa Objective-C không rỗng và không thể rỗng trong phương pháp API dựa trên khối


105

Hãy xem xét phương pháp sau

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

Với các từ khóa mới nonnullnullable chú thích, chúng ta có thể làm phong phú nó như sau:

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

nhưng chúng tôi cũng nhận được cảnh báo này:

Con trỏ thiếu bộ định nghĩa kiểu nullability (__nonnull hoặc __nullable)

Nó đề cập đến tham số thứ ba (khối một).

Các tài liệu không bao gồm với các ví dụ làm thế nào để xác định giá trị null của các thông số khối. Nó nói nguyên văn

Bạn có thể sử dụng các biểu mẫu không gạch dưới có giá trị nullable và nonnull ngay sau dấu ngoặc đơn đang mở, miễn là kiểu đó là một đối tượng đơn giản hoặc con trỏ khối.

Tôi đã thử đặt một trong hai từ khóa cho khối (ở bất kỳ vị trí nào) mà không gặp may. Cũng đã thử các biến thể có tiền tố gạch dưới ( __nonnull__nullable).

Do đó, câu hỏi của tôi là: làm cách nào để chỉ định ngữ nghĩa nullability cho các tham số khối?

Câu trả lời:


128

Điều này dường như đang hoạt động

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

Bạn cần chỉ định khả năng vô hiệu cho cả khối và các tham số của nó ...

CHỈNH SỬA: Để biết thêm thông tin, hãy xem Blog Swift


Làm thế nào để điều đó làm việc với NSError **loại? Tôi dường như không thể làm cho trình biên dịch hài lòng.
duhanebel

3
Theo blog nhanh: 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 Câu trả lời được đưa ra trong stackoverflow.com/questions/33198597/… : Lỗi (NSError * _Nullable * _Nullable)
Elise van Looij

33

Theo Apple Blog ("Nullability and Objective-C") , bạn có thể sử dụng

NS_ASSUME_NONNULL_BEGINNS_ASSUME_NONNULL_END.

Trong các vùng này, bất kỳ loại con trỏ đơn giản nào cũng sẽ được giả định là nonnull. Sau đó, bạn chỉ có thể thêm nullableđối tượng nullable, giống như

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
  • nếu lỗiNSError **loại, nênNSError * _Nullable * _Nullable
  • nếu đối tượng là id *loại, sử dụng tốt hơn id _Nullable * _Nonnull, nó phụ thuộc (có thể bạn muốn một _Nullable id * _Nullableloại).
  • nếu đối tượng là NSObject *loại, bạn cần đặt chú thích sau con trỏ, như thế nàyNSObject * _Nullable * _Nonnull

Ghi chú

_Nonnull_Nullablenên được sử dụng sau con trỏ hoặc id(Apple làm trong mã ví dụ AAPLListItem * _Nullable), nhưng các biểu mẫu không gạch dưới nonnullnullablecó thể được sử dụng sau dấu ngoặc đơn mở.

Tuy nhiên, trong trường hợp phổ biến, có một cách tốt hơn nhiều để viết các chú thích này: trong khai báo phương thức, bạn có thể sử dụng các biểu mẫu không gạch dưới nullablenonnullngay sau dấu ngoặc đơn mở, miễn là kiểu đó là một đối tượng đơn giản hoặc con trỏ khối.

kiểm tra thêm trong "Tính vô hiệu và Mục tiêu-C"

Để đảm bảo an toàn, có một số ngoại lệ đối với quy tắc này:

  • typedefcác kiểu thường không có khả năng vô hiệu vốn có — chúng có thể dễ dàng là có thể nullable hoặc không thể nullable tùy thuộc vào ngữ cảnh. Do đó, typedefcác loại không được giả định là có nonnull, ngay cả trong các khu vực được kiểm toán.
  • Các loại con trỏ phức tạp hơn như id *phải được chú thích rõ ràng. Ví dụ, để chỉ định một con trỏ không thể nullable đến một tham chiếu đối tượng có thể nullable, hãy sử dụng _Nullable id * _Nonnull.
  • Kiểu cụ thể NSError **thường được sử dụng để trả về lỗi thông qua các tham số của phương thức, đến nỗi nó luôn được giả định là một con trỏ có thể null tới một NSErrortham chiếu có thể chạy được.

_Nullable id * _Nonnullthể bị nhầm lẫn, id _Nullable * _Nonnulllà sự hiểu biết tốt hơn.

_Nonnull_Nullablenên sử dụng sau con trỏ hoặc id(Apple làm trong mã ví dụAAPLListItem * _Nullable )


Đối với thuộc tính yếu, _Nullable được áp dụng.
Dongjin Suh

3

Bạn cũng có thể làm như sau:

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

Nó chỉ phụ thuộc vào cú pháp nào bạn thích hơn.


2

Để xác định phần hoàn thành trong tệp tiêu đề, tôi đã làm điều này

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

Tất nhiên, tôi đồng ý với câu trả lời được chấp nhận.


0

Từ blog của nhà phát triển apple : The Core: _Nullable và _Nonnull

bạn có thể sử dụng các biểu mẫu không gạch dưới là nullable và nonnull ngay sau dấu ngoặc đơn đang mở , miễn là kiểu là một đối tượng đơn giản hoặc con trỏ khối.

Các biểu mẫu không gạch dưới đẹp hơn các biểu mẫu gạch dưới, nhưng bạn vẫn cần áp dụng chúng cho mọi loại trong tiêu đề của mình .


Ừ nhưng không gạch dưới (đẹp hơn) những người không làm việc trong tờ khai khối
Paul Bruneau

-2

Đây là những gì tôi đã sử dụng cho trường hợp NSError **:

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

1
Như Apple đã nói, NSError **bạn không cần phải chỉ định khả năng vô hiệu của nó.
DawnSong
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.