Come utilizzare parole chiave Objective-C non null e nullable nel metodo API basato su blocchi


105

Considera il seguente metodo

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

Con le parole chiave nuove nonnulle nullable annotazioni possiamo arricchirlo come segue:

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

ma riceviamo anche questo avviso:

Nel puntatore manca un identificatore di tipo nullability (__nonnull o __nullable)

Si riferisce al terzo parametro (quello del blocco).

La documentazione non copre con esempi come specificare il nullability dei parametri di blocco. Afferma testualmente

È possibile utilizzare i moduli senza sottolineatura nullable e nonnull immediatamente dopo una parentesi aperta, purché il tipo sia un oggetto semplice o un puntatore a un blocco.

Ho provato a mettere una delle due parole chiave per il blocco (in qualsiasi posizione) senza fortuna. Ho anche provato le varianti con il carattere di sottolineatura ( __nonnulle__nullable ).

Pertanto la mia domanda è: come posso specificare la semantica nullability per i parametri di blocco?

Risposte:


128

Questo sembra funzionare

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

È necessario specificare nullability sia per il blocco che per i suoi parametri ...

MODIFICA: per ulteriori informazioni, consulta Swift Blog


Come funziona con il NSError **tipo? Non riesco a rendere felice il compilatore.
duhanebel

3
Secondo il blog swift: 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 La risposta è data in stackoverflow.com/questions/33198597/... : (NSError * * _Nullable _Nullable) Errore
Elise van Looij

33

Secondo il blog di Apple ("Nullability and Objective-C") , puoi usare

NS_ASSUME_NONNULL_BEGINe NS_ASSUME_NONNULL_END.

All'interno di queste regioni, si presume che sia qualsiasi tipo di puntatore semplice nonnull. Quindi puoi semplicemente aggiungere nullableoggetti nullable, che come

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
  • se l' errore èNSError ** tipo, dovrebbe essereNSError * _Nullable * _Nullable
  • se l'oggetto è di id *tipo, usalo meglio id _Nullable * _Nonnull, dipende (potresti volere un file_Nullable id * _Nullable tipo).
  • se l'oggetto è di NSObject *tipo, è necessario inserire un'annotazione dopo il puntatore, in questo modoNSObject * _Nullable * _Nonnull

Nota

_Nonnulle _Nullabledovrebbe essere usato dopo il puntatore o id(Apple lo fa nel codice di esempio AAPLListItem * _Nullable), ma i moduli non sottolineati nonnulle nullablepossono essere usati dopo una parentesi aperta.

Tuttavia, nel caso comune c'è un modo molto più carino per scrivere queste annotazioni: all'interno delle dichiarazioni di metodo puoi usare le forme non sottolineate nullablee nonnullimmediatamente dopo una parentesi aperta, purché il tipo sia un semplice oggetto o un puntatore a un blocco.

controlla di più in "Nullability e Objective-C"

Per sicurezza, ci sono alcune eccezioni a questa regola:

  • typedefi tipi di solito non hanno un nullability intrinseco, possono essere facilmente annullabili o non annullabili a seconda del contesto. Pertanto, typedefnon si presume che i tipi siano nonnull, nemmeno all'interno delle regioni controllate.
  • Tipi di puntatori più complessi come id *devono essere annotati in modo esplicito. Ad esempio, per specificare un puntatore non nullable a un riferimento a un oggetto nullable, utilizzare_Nullable id * _Nonnull .
  • Il tipo particolare NSError **viene utilizzato così spesso per restituire errori tramite i parametri del metodo che si presume sempre che sia un puntatore nullable a un NSErrorriferimento nullable .

La _Nullable id * _Nonnullpuò essere confuso, id _Nullable * _Nonnullè una migliore comprensione.

_Nonnulle _Nullabledovrebbe essere usato dopo il puntatore o id(Apple lo fa nel codice di esempioAAPLListItem * _Nullable )


Per la proprietà debole, viene applicato _Nullable.
Dongjin Suh

3

Puoi anche fare così:

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

Dipende solo dalla sintassi che ti piace di più.


2

Per definire i completamenti in un file di intestazione ho fatto questo

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

Ovviamente sono d'accordo con la risposta accettata.


0

Dal blog degli sviluppatori Apple : The Core: _Nullable e _Nonnull

è possibile utilizzare le forme senza sottolineatura nullable e nonnull immediatamente dopo una parentesi aperta , purché il tipo sia un oggetto semplice o un puntatore a un blocco.

I moduli non sottolineati sono più belli di quelli sottolineati, ma dovresti comunque applicarli a ogni tipo nell'intestazione .


Sì, ma quelli non di sottolineatura (più belli) non funzionano nelle dichiarazioni di blocco
Paul Bruneau

-2

Ecco cosa ho usato per il caso NSError **:

-(BOOL) something:(int)number withError:(NSError *__autoreleasing  __nullable * __nullable)error;

1
Come ha detto Apple , NSError **non è necessario specificare la sua annullabilità.
DawnSong
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.