उद्देश्य-सी में अशक्त, __nullable और _Nullable के बीच अंतर


154

Xcode 6.3 के साथ, उद्देश्य-सी में एपीआई के इरादे को बेहतर ढंग से व्यक्त करने के लिए (और बेहतर स्विफ्ट समर्थन सुनिश्चित करने के लिए) नए एनोटेशन पेश किए गए थे । वे एनोटेशन बेशक थे nonnull, nullableऔर null_unspecified

लेकिन Xcode 7 के साथ, ऐसी कई चेतावनी दिखाई दे रही हैं जैसे:

सूचक एक अशक्तता प्रकार विनिर्देशक (_Nonnull, _Nullable या _Null_unspecified) को याद कर रहा है।

इसके अलावा, Apple अपने C कोड ( स्रोत ) को चिह्नित करते हुए एक अन्य प्रकार की अशक्तता निर्दिष्ट करता है।

CFArrayRef __nonnull CFArrayCreate(
CFAllocatorRef __nullable allocator, const void * __nonnull * __nullable values, CFIndex numValues, const CFArrayCallBacks * __nullable callBacks);

इस प्रकार, अब, हमारे पास ये 3 अलग-अलग अशक्तताएं हैं:

  • nonnull, nullable,null_unspecified
  • _Nonnull, _Nullable,_Null_unspecified
  • __nonnull, __nullable,__null_unspecified

भले ही मुझे पता है कि क्यों और कहां किस एनोटेशन का उपयोग करना है, मैं थोड़ा भ्रमित हो रहा हूं कि मुझे किस प्रकार के एनोटेशन का उपयोग करना चाहिए, कहां और क्यों। यह वही है जो मैं इकट्ठा कर सकता था:

  • गुण का उपयोग करना चाहिए के लिए nonnull, nullable, null_unspecified
  • मैं का उपयोग करना चाहिए विधि पैरामीटर के लिए nonnull, nullable, null_unspecified
  • सी तरीकों का उपयोग करना चाहिए के लिए __nonnull, __nullable, __null_unspecified
  • ऐसे दोहरे संकेत का उपयोग करना चाहिए अन्य मामलों के लिए _Nonnull, _Nullable, _Null_unspecified

लेकिन मैं अभी भी उलझन में हूं कि हमारे पास इतने सारे एनोटेशन क्यों हैं जो मूल रूप से एक ही काम करते हैं।

तो मेरा सवाल है:

उन एनोटेशन के बीच सटीक अंतर क्या है, उन्हें सही तरीके से कैसे और क्यों रखा जाए?


3
मैंने उस पोस्ट को पढ़ा है, लेकिन यह अंतर नहीं बताता है और हमारे पास अब 3 अलग-अलग प्रकार के एनोटेशन क्यों हैं और मैं वास्तव में समझना चाहता हूं कि वे तीसरे प्रकार को क्यों जोड़ते हैं।
लेगलेस सेप

2
यह वास्तव में @ Cy-4AH की मदद नहीं करता है और आप इसे जानते हैं। :)
लेगलेस

@Legoless, क्या आप वाकई इसे ध्यान से पढ़ रहे हैं? यह ठीक से समझाता है कि आपको उनका उपयोग कहां और कैसे करना चाहिए, ऑडिट किए गए स्कोप क्या हैं, जब आप दूसरे को बेहतर पठनीयता, संगतता कारणों, आदि, आदि के लिए उपयोग कर सकते हैं ... आप नहीं जानते होंगे कि आप वास्तव में क्या पूछना चाहते हैं, लेकिन उत्तर स्पष्ट रूप से लिंक के तहत है। शायद यह सिर्फ मेरे लिए है, लेकिन मुझे नहीं लगता कि उनके उद्देश्य की व्याख्या करने, उस सरल स्पष्टीकरण को यहां एक उत्तर के रूप में यहां पर चिपकाने और चिपकाने के लिए कोई और स्पष्टीकरण आवश्यक होगा, यह वास्तव में अजीब होगा, मुझे लगता है। :(
हॉलेक्स

2
यह कुछ हिस्सों को स्पष्ट करता है, लेकिन नहीं, मुझे अभी भी समझ नहीं आया कि हमारे पास पहले एनोटेशन क्यों नहीं हैं। यह केवल यह बताता है कि वे __nullable से _Nullable क्यों गए, लेकिन क्यों नहीं हमें _Nullable की भी आवश्यकता है, अगर हमारे पास nullable है। और यह भी स्पष्ट नहीं है कि Apple अभी भी __nullable का उपयोग अपने कोड में क्यों करता है।
लेगलेस सेप

जवाबों:


152

से clang प्रलेखन :

अशक्तता (प्रकार) क्वालिफायर व्यक्त करता है कि क्या दिए गए पॉइंटर प्रकार का मान शून्य ( _Nullableक्वालिफायर) हो सकता है, अशक्त ( क्वालिफायर) के लिए कोई परिभाषित अर्थ नहीं है _Nonnull, या जिसके लिए अशक्त का उद्देश्य अस्पष्ट है ( _Null_unspecifiedक्वालिफायर) । क्योंकि अशक्तता क्वालिफायर टाइप सिस्टम के भीतर व्यक्त की जाती है, वे nonnullऔर returns_nonnullविशेषताओं की तुलना में अधिक सामान्य होते हैं , जिससे एक को व्यक्त करने की अनुमति मिलती है (उदाहरण के लिए) नॉनबल पॉइंटर्स की एक सरणी के लिए एक अशक्त सूचक। Nullability क्वालिफ़ायर सूचक के दाईं ओर लिखे जाते हैं जिस पर वे लागू होते हैं।

, तथा

ऑब्जेक्टिव-सी में, नॉलेबिलिटी क्वालिफायर के लिए एक वैकल्पिक वर्तनी है, जिसका उपयोग ऑब्जेक्टिव-सेंसिटिव, नॉन-अंडरस्क्राइब्ड कीवर्ड का उपयोग करके ऑब्जेक्टिव-सी के तरीकों और प्रॉपर्टीज में किया जा सकता है।

तो विधि रिटर्न और मापदंडों के लिए आप डबल-अंडरस्कोर किए गए संस्करणों का उपयोग कर सकते हैं __nonnull/ __nullable/ __null_unspecifiedया एकल-अंडरस्कोर वाले के बजाय, या बिना-अंडरस्कोर वाले के बजाय। अंतर यह है कि सिंगल और डबल अंडरस्कोर वाले को टाइप डेफिनिशन के बाद रखा जाना चाहिए, जबकि नॉन-अंडरस्कोर वाले को टाइप डेफिनिशन से पहले रखा जाना चाहिए।

इस प्रकार, निम्नलिखित घोषणाएं बराबर हैं और सही हैं:

- (nullable NSNumber *)result
- (NSNumber * __nullable)result
- (NSNumber * _Nullable)result

मापदंडों के लिए:

- (void)doSomethingWithString:(nullable NSString *)str
- (void)doSomethingWithString:(NSString * _Nullable)str
- (void)doSomethingWithString:(NSString * __nullable)str

गुणों के लिए:

@property(nullable) NSNumber *status
@property NSNumber *__nullable status
@property NSNumber * _Nullable status

हालाँकि कुछ चीजें जटिल हो जाती हैं जब डबल पॉइंटर्स या ब्लॉक, जो शून्य से अलग कुछ लौटते हैं, शामिल होते हैं, क्योंकि गैर-अंडरस्कोर वालों को यहां अनुमति नहीं है:

- (void)compute:(NSError *  _Nullable * _Nullable)error
- (void)compute:(NSError *  __nullable * _Null_unspecified)error;
// and all other combinations

ब्लॉक के मापदंडों के रूप में स्वीकार करने वाले तरीकों के साथ, कृपया ध्यान दें कि nonnull/ nullableक्वालिफायर ब्लॉक पर लागू होता है, और इसके रिटर्न प्रकार पर नहीं, इस प्रकार निम्नलिखित हैं:

- (void)executeWithCompletion:(nullable void (^)())handler
- (void)executeWithCompletion:(void (^ _Nullable)())handler
- (void)executeWithCompletion:(void (^ __nullable)())handler

यदि ब्लॉक का रिटर्न मान है, तो आपको अंडरस्कोर संस्करणों में से एक में मजबूर किया जाता है:

- (void)convertObject:(nullable id __nonnull (^)(nullable id obj))handler
- (void)convertObject:(id __nonnull (^ _Nullable)())handler
- (void)convertObject:(id _Nonnull (^ __nullable)())handler
// the method accepts a nullable block that returns a nonnull value
// there are some more combinations here, you get the idea

निष्कर्ष के रूप में, आप दोनों का उपयोग कर सकते हैं, जब तक कंपाइलर क्वालिफायर को असाइन करने के लिए आइटम का निर्धारण कर सकता है।


2
ऐसा लगता है कि अंडरस्कोर संस्करणों का उपयोग हर जगह किया जा सकता है, इसलिए मुझे लगता है कि मैं कुछ जगहों पर अंडरस्कोर किए गए संस्करणों का उपयोग करने के बजाय लगातार उनका उपयोग करूंगा, दूसरों में अंडरस्कोर के बिना। सही बात?
वड़ादि कार्तिक

@KartickVaddadi हाँ, सही है, आप लगातार एकल अंडरस्कोर, या डबल अंडरस्कोर संस्करण का उपयोग कर सकते हैं।
क्रिस्टिक

_Null_unspecifiedस्विफ्ट में यह वैकल्पिक करने के लिए अनुवाद? गैर-वैकल्पिक या क्या?
हनी

1
@ हनी _Null_unspecified स्विफ्ट में आयात किया गया है जैसा कि अनप्लग्ड अनट्रैप्ड ऑप्शनल
क्रिस्टिक

1
@ क्रिकट अहा। मुझे लगता है कि यह इसका डिफ़ॉल्ट मूल्य है ... क्योंकि जब मैंने निर्दिष्ट नहीं किया था कि मुझे इम्प्लांटली अलिखित वैकल्पिक मिल रहा था ...
हनी

28

से स्विफ्ट ब्लॉग :

इस फीचर को Xcode 6.3 में __nullable और __nonnull के साथ पहली बार जारी किया गया था। तीसरे पक्ष के पुस्तकालयों के साथ संभावित संघर्षों के कारण, हमने उन्हें Xcode 7 में बदलकर _Nullable और _Nonnull के रूप में देखा है जो आप यहाँ देख रहे हैं। हालाँकि, Xcode 6.3 के साथ संगतता के लिए हमने नए नामों का विस्तार करने के लिए मैक्रोज़ __nullable और __nonnull को पूर्वनिर्धारित किया है।


4
संक्षेप में, एकल और डबल अंडरस्कोर संस्करण समान हैं।
वड़ादि कार्तिक

4
Xcode 7.0 रिलीज़ नोट में भी प्रलेखित: "डबल-अंडरस्कोर नेलबिलिटी क्वालिफायर (__nullable, __nonnull, और __null_unspecified) का नाम बदलकर एक एकल अक्षर के साथ एक एकल अक्षर का उपयोग करने के लिए नाम दिया गया है: _Nullable, _Nonnull, और _Null_unspecified; क्रमशः)। पुराने डबल-अनिर्दिष्ट नामों से स्रोत संगतता के लिए नए नामों की मैपिंग। (21530726) "
कॉसिन

25

मुझे यह लेख बहुत पसंद आया , इसलिए मैं केवल वही दिखा रहा हूँ जो लेखक ने लिखा था: https://swiftunboxed.com/interop/objc-nullability-annotations/

  • null_unspecified:एक स्विफ्ट के पुलों को अव्यवस्थित-अलिखित वैकल्पिक। यह डिफ़ॉल्ट है
  • nonnull: मान शून्य नहीं होगा; एक नियमित संदर्भ के लिए पुल।
  • nullable: मान शून्य हो सकता है; एक वैकल्पिक के लिए पुलों।
  • null_resettable: पढ़ा जाने पर मूल्य कभी शून्य नहीं हो सकता, लेकिन आप इसे रीसेट करने के लिए इसे शून्य पर सेट कर सकते हैं। केवल गुणों पर लागू होता है।

ऊपर दी गई सूचनाएं, फिर भिन्न होती हैं कि आप उन्हें संपत्तियों या कार्यों / चर के संदर्भ में उपयोग करते हैं :

संकेत बनाम गुण संकेतन

लेख के लेखक ने एक अच्छा उदाहरण भी दिया:

// property style
@property (nonatomic, strong, null_resettable) NSString *name;

// pointer style
+ (NSArray<NSView *> * _Nullable)interestingObjectsForKey:(NSString * _Nonnull)key;

// these two are equivalent!
@property (nonatomic, strong, nullable) NSString *identifier1;
@property (nonatomic, strong) NSString * _Nullable identifier2;

12

बहुत काम है

NS_ASSUME_NONNULL_BEGIN 

और के साथ समापन

NS_ASSUME_NONNULL_END 

यह कोड स्तर 'nullibis' :-) की आवश्यकता को कम कर देगा क्योंकि यह इस बात का बोध कराता है कि सब कुछ गैर-शून्य ( nonnullया _nonnullया __nonnull) है जब तक कि अन्यथा नोट न किया गया हो।

दुर्भाग्य से इसके अपवाद भी हैं ...

  • typedefs माना नहीं जाता है __nonnull(ध्यान दें, nonnullकाम नहीं लगता है, इसका उपयोग करना है बदसूरत सौतेला भाई)
  • id *एक स्पष्ट अशक्त की जरूरत है, लेकिन पाप-कर वाह ( _Nullable id * _Nonnull<- लगता है कि इसका क्या मतलब है ...)
  • NSError ** हमेशा अशक्त माना जाता है

तो अपवादों और असंगत खोजशब्दों के अपवाद के साथ एक ही कार्यक्षमता का उपयोग करते हुए, शायद दृष्टिकोण बदसूरत संस्करणों का उपयोग करना है __nonnull/ __nullable/ __null_unspecifiedऔर जब स्वैप शिकायत करता है ...? शायद यही कारण है कि वे एप्पल हेडर में मौजूद हैं?

दिलचस्प रूप से पर्याप्त है, कुछ ने इसे मेरे कोड में डाल दिया ... मैं कोड (पुराने स्कूल Apple C ++ शैली आदमी) में अंडरस्कोर करता हूं, इसलिए मुझे पूरा यकीन है कि मैंने ये टाइप नहीं किया था लेकिन वे प्रकट हुए (कई का एक उदाहरण):

typedef void ( ^ DidReceiveChallengeBlock ) ( NSURLSessionAuthChallengeDisposition disposition,
                                          NSURLCredential * __nullable credential );

और इससे भी दिलचस्प बात यह है कि, जहाँ यह डाला गया है __nullable गलत है ... (eek @!)

मैं वास्तव में कामना करता हूं कि मैं सिर्फ नॉन-अंडरस्कोर संस्करण का उपयोग कर सकता हूं, लेकिन जाहिर है कि संकलक के साथ उड़ान नहीं भरता क्योंकि यह एक त्रुटि है।

typedef void ( ^ DidReceiveChallengeBlock ) ( NSURLSessionAuthChallengeDisposition disposition,
                                          NSURLCredential * nonnull  credential );

2
नॉन-अंडरस्कोर केवल एक ओपनिंग कोष्ठक के बाद सीधे इस्तेमाल किया जा सकता है, (नॉननुल ... बस जीवन को और अधिक बनाने के लिए, मुझे यकीन है।
एलिस वैन लोइज

मैं आईडी कैसे बनाऊं <> मुझे ऐसा लगता है कि इस उत्तर में बहुत सारा ज्ञान है लेकिन इसमें स्पष्टता का अभाव है।
2

1
@fizzybear ने स्वीकार किया कि मैं आमतौर पर विपरीत दृष्टिकोण अपनाता हूं। पॉइंटर्स मेरे दोस्त हैं और मुझे 90 के दशक की शुरुआत से "नल" / "नील" पॉइंटर की समस्या नहीं हुई। काश, मैं पूरी अशक्त / शून्य करने योग्य चीज बना सकूं। लेकिन इस बिंदु पर, वास्तविक उत्तर उत्तर की पहली 6 पंक्तियों में है। लेकिन आपके प्रश्न के बारे में: कुछ ऐसा नहीं जो मैं (कोई आलोचना नहीं) करूँगा इसलिए मुझे अभी पता नहीं है।
विलियम सेर्नियुक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.