วิธีใช้คีย์เวิร์ด Objective-C แบบ nonnull และ nullable ในวิธี API แบบบล็อก


107

พิจารณาวิธีการต่อไปนี้

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

หมายถึงพารามิเตอร์ที่สาม (บล็อกที่หนึ่ง)

เอกสารไม่ครอบคลุมกับตัวอย่างวิธีการระบุ nullability ของพารามิเตอร์บล็อก มันระบุคำต่อคำ

คุณสามารถใช้รูปแบบที่ไม่ขีดเส้นใต้ที่เป็นค่าว่างและไม่เป็นค่าว่างได้ทันทีหลังจากวงเล็บเปิดตราบใดที่ชนิดนั้นเป็นวัตถุธรรมดาหรือตัวชี้บล็อก

ฉันลองใส่หนึ่งในสองคำหลักสำหรับบล็อก (ในตำแหน่งใดก็ได้) โดยไม่มีโชค ลองใช้รูปแบบที่นำหน้าขีดล่างด้วย ( __nonnullและ__nullable)

ดังนั้นคำถามของฉันคือฉันจะระบุความหมายเชิงโมฆะสำหรับพารามิเตอร์บล็อกได้อย่างไร

คำตอบ:


128

ดูเหมือนว่าจะใช้งานได้

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

คุณต้องระบุ nullability ทั้งสำหรับบล็อกและพารามิเตอร์ ...

แก้ไข: สำหรับข้อมูลเพิ่มเติมโปรดดูSwift Blog


มันทำงานอย่างไรกับNSError **ประเภท? ดูเหมือนจะทำให้คอมไพเลอร์มีความสุขไม่ได้
duhanebel

3
อ้างอิงจากบล็อกของ 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 คำตอบอยู่ในstackoverflow.com/questions/33198597/… : (NSError * _Nullable * _Nullable) error
Elise van Looij

33

ตามบล็อกของ Apple ("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ทันทีหลังจากวงเล็บเปิดตราบใดที่ประเภทนั้นเป็นวัตถุธรรมดาหรือตัวชี้บล็อก

ตรวจสอบเพิ่มเติมใน"Nullability and Objective-C"

เพื่อความปลอดภัยมีข้อยกเว้นบางประการสำหรับกฎนี้:

  • typedefประเภทมักจะไม่มีความสามารถเป็นโมฆะโดยธรรมชาติ - สามารถเป็นโมฆะหรือไม่เป็นโมฆะได้อย่างง่ายดายขึ้นอยู่กับบริบท ดังนั้นจึงtypedefไม่ถือว่าประเภทเป็นประเภทnonnullแม้จะอยู่ในภูมิภาคที่ตรวจสอบแล้วก็ตาม
  • ประเภทตัวชี้ที่ซับซ้อนมากขึ้นเช่น id *ต้องใส่คำอธิบายประกอบอย่างชัดเจน ตัวอย่างเช่นในการระบุตัวชี้ไม่ใช่ nullable ไปอ้างอิงวัตถุ nullable _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

จากบล็อกของนักพัฒนาแอปเปิ้ล: The Core: _Nullable และ _Nonnull

คุณสามารถใช้รูปแบบที่ไม่ขีดเส้นใต้ที่เป็นค่าว่างและไม่เป็นค่าว่างได้ทันทีหลังจากวงเล็บเปิดตราบใดที่ประเภทนั้นเป็นวัตถุธรรมดาหรือตัวชี้บล็อก

รูปแบบที่ไม่ได้เน้นย้ำความเป็น nicer กว่าคนที่ได้เน้นย้ำ แต่ คุณจะยังคงต้องนำไปใช้กับทุกประเภทในส่วนหัวของคุณ


ใช่ แต่คนที่ไม่ขีดล่าง (ดีกว่า) ไม่ทำงานในการประกาศบล็อก
Paul Bruneau

-2

นี่คือสิ่งที่ฉันใช้สำหรับเคส NSError **:

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

1
ดังที่Appleกล่าวเพราะNSError **คุณไม่จำเป็นต้องระบุความเป็นโมฆะ
DawnSong
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.