wake-up-neo.com

Verwendung von nicht vollständigen und nullfähigen Objective-C-Schlüsselwörtern in blockbasierten API-Methoden

Betrachten Sie die folgende Methode

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

Mit den neuen nonnull und nullableAnmerkungsschlüsselwörtern können wir es wie folgt anreichern:

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

aber wir bekommen auch diese Warnung:

Dem Zeiger fehlt ein NULL-Typ-Bezeichner (__nonnull oder __nullable)

Es bezieht sich auf den dritten Parameter (den ersten Block).

Die Dokumentation behandelt nicht mit Beispielen, wie die Nullwertfähigkeit von Blockparametern angegeben werden kann. Es heißt wörtlich

Sie können die nicht unterstrichenen Formulare verwenden, die unmittelbar nach einer offenen Klammer nullbar und ungültig sind, sofern der Typ ein einfaches Objekt oder ein Blockzeiger ist.

Ich habe versucht, eines der beiden Schlüsselwörter für den Block (in einer beliebigen Position) ohne Glück zu setzen. Habe auch die mit Unterstrich versehenen Varianten ausprobiert (__nonnull und __nullable).

Daher lautet meine Frage: Wie kann ich die Nullbarkeitssemantik für Blockparameter festlegen?

93

Das scheint zu funktionieren

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

Sie müssen die Nullwertfähigkeit sowohl für den Block als auch für seine Parameter angeben ...

BEARBEITEN: Weitere Informationen finden Sie unter Swift Blog

114
Fabio Ritrovato

Laut Apple Blog ("Nullability and Objective-C") können Sie verwenden

NS_ASSUME_NONNULL_BEGIN Und NS_ASSUME_NONNULL_END.

Innerhalb dieser Regionen wird angenommen, dass jeder einfache Zeigertyp nonnull ist. Dann können Sie einfach nullable für ein nullbares Objekt hinzufügen, das gefällt

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
  • wenn error vom Typ NSError ** ist, sollte NSError * _Nullable * _Nullable sein.
  • wenn das Objekt vom Typ id * ist, verwenden Sie besser id _Nullable * _Nonnull, es hängt davon ab (möglicherweise möchten Sie einen _Nullable id * _Nullable - Typ).
  • wenn das Objekt vom Typ NSObject * ist, müssen Sie eine Anmerkung nach dem Zeiger einfügen, wie folgt: NSObject * _Nullable * _Nonnull

Hinweis

_Nonnull Und _Nullable Sollten nach dem Zeiger oder id verwendet werden (Apple tut dies im Beispielcode AAPLListItem * _Nullable), Aber die nicht unterstrichenen Formen nonnull und nullable können nach einer offenen Klammer verwendet werden.

In der Regel gibt es jedoch eine viel schönere Möglichkeit, diese Annotationen zu schreiben: Innerhalb von Methodendeklarationen können Sie die nicht unterstrichenen Formulare nullable und nonnull unmittelbar nach einer offenen Klammer verwenden, solange die Typ ist ein einfaches Objekt oder ein Blockzeiger.

weitere Informationen finden Sie in "Nullability and Objective-C"

Aus Sicherheitsgründen gibt es einige Ausnahmen von dieser Regel:

  • typedef -Typen haben normalerweise keine inhärente NULL-Fähigkeit. Sie können je nach Kontext entweder NULL-fähig oder nicht-NULL-fähig sein. Daher wird nicht angenommen, dass typedef - Typen nonnull sind, auch nicht in geprüften Regionen.
  • Komplexere Zeigertypen wie id * Müssen explizit mit Anmerkungen versehen werden. Verwenden Sie beispielsweise _Nullable id * _Nonnull, Um einen nicht nullwertfähigen Zeiger auf eine nullwertfähige Objektreferenz anzugeben.
  • Der bestimmte Typ NSError ** Wird so oft verwendet, um Fehler über Methodenparameter zurückzugeben, dass immer davon ausgegangen wird, dass es sich um einen nullfähigen Zeiger auf eine nullfähige NSError -Referenz handelt.

Der _Nullable id * _Nonnull Kann verwechselt werden, id _Nullable * _Nonnull Ist besser verständlich.

_Nonnull Und _Nullable Sollten nach dem Zeiger oder id verwendet werden (Apple tut dies im Beispielcode AAPLListItem * _Nullable)

29
likid1412

Das können Sie auch so machen:

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

Es kommt nur darauf an, welche Syntax Sie bevorzugen.

3
OlDor

Um Vervollständigungen in einer Header-Datei zu definieren, habe ich dies getan

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

Natürlich stimme ich der akzeptierten Antwort zu.

2
Krishna Kumar

Von Apple Entwicklerblog : The Core: _Nullable und _Nonnull

sie können die nicht unterstrichenen Formen nullable und nonnull unmittelbar nach einer offenen Klammer verwenden, solange der Typ ein einfaches Objekt oder ein Blockzeiger ist.

Die nicht unterstrichenen Formulare sind besser als die unterstrichenen, aber Sie müssen sie trotzdem auf jeden Typ in Ihrer Kopfzeile anwenden.

0
Parag Bafna