Betrachten Sie die folgende Methode
- (void)methodWithArg:(NSString *)arg1 andArg:(NSString *)arg2 completionHandler:(void (^)(NSArray *results, NSError *error))completionHandler;
Mit den neuen nonnull
und nullable
Anmerkungsschlü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?
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
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
NSError **
ist, sollte NSError * _Nullable * _Nullable
sein.id *
ist, verwenden Sie besser id _Nullable * _Nonnull
, es hängt davon ab (möglicherweise möchten Sie einen _Nullable id * _Nullable
- 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
undnonnull
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, dasstypedef
- Typennonnull
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ähigeNSError
-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
)
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.
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.
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.