Al fine di migliorare l’integrazione tra Objective-C e Swift (ma anche di rendere il codice Objective-C più sicuro) Apple ha introdotto la possibilità di specificare se una certa referenza a un oggetto possa o meno contenere valori nulli.
Immaginiamo di creare una classe Movie, definita come segue:
// File: Movie.h
@interface Movie : NSObject
@property (retain, readwrite) NSString * title;
@property (retain, readwrite) NSString * director;
@property (retain, readwrite) NSDate * releaseDate;
@end
// File: Movie.m
#import "Movie.h"
@implementation Movie
@end
Non abbiamo alcuna garanzia che title
, director
e releaseDate
siano popolati. Per risolvere questo problema, possiamo usare le keywork _Nullable
e _Nonnull
.
#import <Foundation/Foundation.h>
@interface Movie : NSObject
@property (retain, readwrite) NSString * _Nonnull title;
@property (retain, readwrite) NSString * _Nonnull director;
@property (retain, readwrite) NSDate * _Nullable releaseDate;
@end
Con questo nuovo codice, stiamo indicando al compilatore che title
e director
dovranno essere sempre popolate. Al contrario, releaseDate
potrà contenere dei valori nulli.
Facciamo subito un test. Apriamo il file main.m e incolliamo il seguente codice:
@import Foundation;
#import "Movie.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Movie * movie = [Movie new];
movie.title = nil;
}
return 0;
}
Con l’istruzione movie.title = nil
stiamo cercando di assegnare un valore nil
alla property title
. Se proviamo a compilare (CMD + B) otterremo il seguente warning dal compilatore:
Null passed to a callee that requires a non-null argument
nullable & nonnull
Per comodità vengono fornite altre 2 keyword (tutte minuscole) che possiamo usare per indicare se un valore nil
è accettato.
Vediamo come aggiornare il codice precedente:
#import <Foundation/Foundation.h>
@interface Movie : NSObject
@property (retain, readwrite, nonnull) NSString * title;
@property (retain, readwrite, nonnull) NSString * director;
@property (retain, readwrite, nullable) NSDate * releaseDate;
@end
Inoltre volendo creare un initializer per l’oggetto Movie
, potremmo scrivere nel file Movie.m:
#import "Movie.h"
@implementation Movie
- (instancetype)init:(nonnull NSString*)title
director:(nonnull NSString*)director
releaseDate:(nullable NSDate*)releaseDate {
if (self = [super init]) {
self.title = title;
self.director = director;
self.releaseDate = releaseDate;
return self;
}
return nil;
}
@end