Verwendung nicht nullter und nullfähiger Objective-C-Schlüsselwörter in blockbasierten API-Methoden

105

Betrachten Sie die folgende Methode

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

Mit den Schlüsselwörtern new nonnullund nullable annotation können wir sie 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 Nullfähigkeitstyp-Bezeichner (__nonnull oder __nullable).

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

Die Dokumentation enthält keine Beispiele für die Angabe der Nullbarkeit von Blockparametern. Es heißt wörtlich

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

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

Daher lautet meine Frage: Wie kann ich die Nullfähigkeitssemantik für Blockparameter angeben?

Albertodebortoli
quelle

Antworten:

128

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 Nullfähigkeit sowohl für den Block als auch für seine Parameter angeben ...

BEARBEITEN: Weitere Informationen finden Sie unter Swift Blog

Fabio Ritrovato
quelle
Wie funktioniert das mit dem NSError **Typ? Ich kann den Compiler nicht glücklich machen.
Duhanebel
3
Laut dem schnellen Blog: 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 Die Antwort ist in stackoverflow.com/questions/33198597/… gegeben : (NSError * _Nullable * _Nullable) Fehler
Elise van Looij
33

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

NS_ASSUME_NONNULL_BEGINund NS_ASSUME_NONNULL_END.

Innerhalb dieser Regionen wird jeder einfache Zeigertyp angenommen nonnull. Dann können Sie einfach nullablefür nullbare Objekte hinzufügen , die mögen

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 Fehler ist NSError **Typ, sollteNSError * _Nullable * _Nullable
  • Wenn das Objekt ein id *Typ ist id _Nullable * _Nonnull, hängt es besser davon ab (möglicherweise möchten Sie einen _Nullable id * _NullableTyp).
  • Wenn das Objekt vom NSObject *Typ ist, müssen Sie wie folgt eine Anmerkung nach dem Zeiger setzenNSObject * _Nullable * _Nonnull

Hinweis

_Nonnullund _Nullablesollte nach Zeiger oder id(Apple im Beispielcode AAPLListItem * _Nullable) verwendet werden, aber die nicht unterstrichenen Formen nonnullund nullablekönnen nach einer offenen Klammer verwendet werden.

Im allgemeinen Fall gibt es jedoch eine viel schönere Möglichkeit, diese Anmerkungen zu schreiben: Innerhalb von Methodendeklarationen können Sie die nicht unterstrichenen Formulare nullableund nonnullunmittelbar nach einer offenen Klammer verwenden, sofern der Typ ein einfaches Objekt oder ein Blockzeiger ist.

Weitere Informationen finden Sie unter "Nullability and Objective-C".

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

  • typedefTypen haben normalerweise keine inhärente Nullbarkeit - sie können je nach Kontext leicht entweder nullbar oder nicht nullbar sein. Daher wird typedefnicht angenommen, dass es sich um Typen handelt nonnull, auch nicht innerhalb geprüfter Regionen.
  • Komplexere Zeigertypen wie id *müssen explizit mit Anmerkungen versehen werden. Verwenden Sie beispielsweise, um einen nicht nullbaren Zeiger auf eine nullbare Objektreferenz anzugeben _Nullable id * _Nonnull.
  • Der bestimmte Typ NSError **wird so oft verwendet, um Fehler über Methodenparameter zurückzugeben, dass immer davon ausgegangen wird, dass er ein nullbarer Zeiger auf eine nullbare NSErrorReferenz ist.

Das _Nullable id * _Nonnullkann verwirrt werden, id _Nullable * _Nonnullist besser zu verstehen.

_Nonnullund _Nullablesollte nach Zeiger oder verwendet werden id(Apple tut dies im BeispielcodeAAPLListItem * _Nullable )

likid1412
quelle
Für schwache Eigenschaften wird _Nullable angewendet.
Dongjin Suh
3

Sie können auch Folgendes tun:

- (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 Ihnen besser gefällt.

OlDor
quelle
2

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.

Krishna Kumar
quelle
0

Aus dem Apple- Entwicklerblog : The Core: _Nullable und _Nonnull

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

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

Parag Bafna
quelle
Ja, aber die nicht unterstrichenen (netteren) funktionieren nicht in Blockdeklarationen
Paul Bruneau
-2

Folgendes habe ich für den Fall NSError ** verwendet:

-(BOOL) something:(int)number withError:(NSError *__autoreleasing  __nullable * __nullable)error;
Kevin
quelle
1
Wie Apple bereits sagte, NSError **müssen Sie die Nullbarkeit nicht angeben.
DawnSong