2015-09-08 6 views
107

Mit Xcode 6.3 wurden neue Annotationen eingeführt, um die Intention von APIs in Objective-C besser zum Ausdruck zu bringen (und natürlich eine bessere Swift-Unterstützung sicherzustellen). Diese Anmerkungen waren natürlich nonnull, nullable und null_unspecified.Unterschied zwischen Nullable, __nullable und _Nullable in Objective-C

Aber mit Xcode 7 gibt es viele Warnungen erscheinen, wie zum Beispiel:

Pointer is missing a nullability type specifier (_Nonnull, _Nullable or _Null_unspecified).

Zusätzlich zu, dass Apple eine andere Art von NULL-Zulässigkeit Bezeich verwendet, deren C-Code-Kennzeichnung (source):

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

Also, um es zusammenzufassen, haben wir nun diese drei verschiedenen NULL-Zulässigkeit Anmerkungen:

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

Auch wenn ich weiß, warum und wo die Anmerkung zu verwenden, ich bin durch die leicht verwirrt Art von Anmerkungen sollte ich verwenden, wo und warum. Das ist, was ich sammeln konnte:

  • Für Eigenschaften sollte ich nonnull, nullable, null_unspecified verwenden.
  • Für Methodenparameter sollte ich nonnull, nullable, null_unspecified verwenden.
  • Für C-Methoden sollte ich __nonnull, __nullable, __null_unspecified verwenden.
  • Für andere Fälle, wie Doppelzeiger sollte ich _Nonnull, _Nullable, _Null_unspecified verwenden.

Aber ich bin verwirrt immer noch, warum wir so viele Anmerkungen haben, die im Grunde das gleiche tun.

Also meine Frage ist:

Was zwischen diesen Anmerkungen genauer Unterschied ist, wie man richtig um sie zu platzieren und warum?

+3

Ich habe diesen Beitrag gelesen, aber es erklärt nicht den Unterschied und warum wir jetzt 3 verschiedene Arten von Anmerkungen haben und ich möchte wirklich verstehen warum Sie fügten den dritten Typ hinzu. – Legoless

+2

Das hilft nicht wirklich @ Cy-4AH und Sie wissen es. :) – Legoless

+0

@Legoless, bist du sicher, dass du es sorgfältig gelesen hast? es erklärt genau, wo und wie Sie sie verwenden sollten, was sind die geprüften Bereiche, wenn Sie den anderen für bessere Lesbarkeit, Kompatibilitätsgründe, etc, etc ... verwenden können Sie nicht wissen, was Sie wirklich gerne fragen, aber die Antwort ist eindeutig unter dem Link. es ist vielleicht nur ich, aber ich glaube nicht, dass eine weitere Erklärung notwendig wäre, um ihren Zweck zu erklären, diese einfache Erklärung hier zu kopieren und einzufügen, da eine Antwort hier wirklich peinlich wäre, denke ich. :( – holex

Antwort

109

Von der clangdocumentation:

The nullability (type) qualifiers express whether a value of a given pointer type can be null (the _Nullable qualifier), doesn’t have a defined meaning for null (the _Nonnull qualifier), or for which the purpose of null is unclear (the _Null_unspecified qualifier). Because nullability qualifiers are expressed within the type system, they are more general than the nonnull and returns_nonnull attributes, allowing one to express (for example) a nullable pointer to an array of nonnull pointers. Nullability qualifiers are written to the right of the pointer to which they apply.

und

In Objective-C, there is an alternate spelling for the nullability qualifiers that can be used in Objective-C methods and properties using context-sensitive, non-underscored keywords

Also für Methode zurückgibt und Parameter können Sie die die Doppel unterstrichen Versionen verwenden __nonnull/__nullable/__null_unspecified statt entweder die einfach unterstrichenen oder anstelle der nicht unterstrichenen.Der Unterschied ist, dass die einfach und doppelt unterstrichenen nach der Typdefinition platziert werden müssen, während die nicht unterstrichenen diejenigen vor der Typdefinition platziert werden müssen.

Somit sind die folgenden Erklärungen sind gleichwertig und korrekt sind:

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

Für Parameter:

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

Für Eigenschaften:

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

Dinge jedoch komplizierter, wenn Doppelzeiger oder Blöcke, die etwas anderes als void zurückgeben, werden in Rechnung gestellt lved, da die Nicht-Unterstreichungs derjenigediejenigedasjenige hier nicht erlaubt sind:

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

mit Methoden ähnliches, die Blöcke als Parameter akzeptieren, bitte beachten Sie, dass die nonnull/nullable Qualifier zum Block gelten, und nicht dessen Rückgabetyp, so dass die sind äquivalent:

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

Wenn der Block einen Rückgabewert hat, dann sind Sie in einem der Unterstreichungs Versionen gezwungen:

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

Als Schlussfolgerung können Sie entweder eins verwenden, solange der Compiler das Element bestimmen kann, dem das Qualifikationsmerkmal zugewiesen werden soll.

+1

Es scheint, dass die Unterstreichungs-Versionen überall verwendet werden können, also nehme ich sie wahrscheinlich konsistent, anstatt an einigen Stellen unterstrichene Versionen zu verwenden und solche ohne den Unterstrich in anderen. Korrekt? –

+0

@KartickVaddadi Ja, richtig, Sie können konsistent entweder die einzelnen unterstrichenen oder die doppelt unterstrichenen Versionen verwenden. – Cristik

+0

'_Null_unspecified' in Swift bedeutet dies optional? nicht optional oder was? – Honey

9

Sehr praktisch ist

NS_ASSUME_NONNULL_BEGIN 

und Schließen mit

NS_ASSUME_NONNULL_END 

Dies wird die Notwendigkeit für die Code-Ebene ‚nullibis‘ :-) zunichte machen, wie es Art Sinn macht davon ausgehen, dass alles ist nicht null (oder nonnull oder _nonnull oder __nonnull), sofern nicht anders angegeben.

Leider Ausnahmen von dieser Regel gibt es auch ...

  • typedef s sind nicht als __nonnull angenommen (beachten Sie, nicht nonnull nicht zu funktionieren scheint, haben zu verwenden, es ist hässlich Halbbruder)
  • id * muss eine explizite nullibi aber wow die Sünde Steuern (_Nullable id * _Nonnull < - erraten, was das bedeutet ...)
  • NSError ** ist immer davon ausgegangen, Nullable-

Also mit den Ausnahmen zu den Ausnahmen und den inkonsistenten Keywords, die die gleiche Funktionalität hervorrufen, ist vielleicht der Ansatz, die hässlichen Versionen __nonnull/__nullable/__null_unspecified zu verwenden und zu tauschen, wenn der Compiler sich beschwert ...? Vielleicht existieren sie deshalb in den Apple Headern?

Interessanterweise steckt etwas in meinen Code ...Ich verabscheue Unterstrichen in Code (alte Schule Apple-C++ Stil Typ), damit ich bin absolut sicher, dass ich nicht diese Art haben aber sie erschienen (ein Beispiel von mehreren):

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

Und noch interessanter ist, wo es die __nullable eingefügt falsch ist ... (eEK @!)

ich mir die nicht-Unterstrich-Version verwende nur wirklich will, könnte aber anscheinend mit dem Compiler, dass nicht fliegen, da dies als Fehler gekennzeichnet ist:

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

Nicht Unterstreichung kann nur direkt nach einer öffnenden Klammer verwendet werden, dh (nonnull ... Nur um das Leben interessanter zu machen, bin ich –

23

Von the Swift blog:

This feature was first released in Xcode 6.3 with the keywords __nullable and __nonnull. Due to potential conflicts with third-party libraries, we’ve changed them in Xcode 7 to the _Nullable and _Nonnull you see here. However, for compatibility with Xcode 6.3 we’ve predefined macros __nullable and __nonnull to expand to the new names.

+3

Kurz gesagt, die Versionen mit einfacher und doppelter Unterstreichung sind identisch –

+4

Auch in Xcode 7.0 Release Notes dokumentiert: "Die doppelt unterstrichenen NULL-Qualifikationsmerkmale (__nullable, __nonnull und __null_unspecified) wurden umbenannt, um einen einzelnen Unterstrich mit a zu verwenden Großbuchstaben: _Nullable, _Nonnull bzw. _Null_unspecified. Der Compiler definiert Makro-Mapping von den alten doppelt nicht spezifizierten Namen zu den neuen Namen für die Quellenkompatibilität. (21530726) – Cosyn

17

Ich mochte this article, so zeige ich nur, was der Autor geschrieben: https://swiftunboxed.com/interop/objc-nullability-annotations/

  • null_unspecified: Brücken zu einem Swift implizit ungeöffneten optional. Dies ist der Standard.
  • nonnull: der Wert wird nicht Null sein; Brücken zu einer regelmäßigen Referenz.
  • nullable: der Wert kann Null sein; Brücken zu einem optionalen.
  • null_resettable: Der Wert kann niemals Null sein, wenn er gelesen wird, aber Sie können ihn auf Null setzen, um ihn zurückzusetzen. Gilt nur für Eigenschaften.

Die Bezeichnungen oben, dann unterscheiden, ob Sie sie im Kontext verwenden von Eigenschaften oder Funktionen/Variablen:

Pointers vs. Properties notation

Der Autor des Artikels auch ein schönes Beispiel vorgesehen:

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