Failable Initializers

La versione 1.1 di Swift è appena uscita in concomitanza con Xcode 6.1 ed introduce una nuova funzione: “failable initializers”. L’inizializzazione è quel processo che assegna un valore per ogni proprietà di una classe, che stabilisce le costanti dell’oggetto. In alcuni casi, l’inizializzazione può fallire. Ad esempio, inizializzare un oggetto richiede l’accesso ad una risorsa, come ad esempio il caricamento di un’immagine da un file:

NSImage(contentsOfFile: "swift.png")

Se il file non esiste o per qualche motivo non fosse leggibile, l’inizializzazione del NSImage fallirà. Con Swift versione 1.1, questi errori possono essere segnalati utilizzando un inizializzatore “failable”. Quando si costruisce un oggetto utilizzando un inizializzatore failable, il risultato è un optional che  contiene l’oggetto (quando l’inizializzazione è riuscita) oppure contiene zero (quando l’inizializzazione non riesce). Pertanto, l’inizializzazione di cui sopra dovrebbe gestire il risultato opzionale:

if let image = NSImage(contentsOfFile: "swift.png") {
	// loaded the image successfully
} else {
	// could not load the image
}

Un inizializzatore definito con init può essere reso failable con l’aggiunta di un “? “o un “!” dopo l’inizializzazione.

Ad esempio, si potrebbe aggiungere un inizializzatore failable a Int che tenta di eseguire una conversione da una stringa:

extension Int {
	init?(fromString: String) { 
		if let i = fromString.toInt() {
			// Initialize
			self = i
		} else { 
			// return nil, discarding self is implied
			return nil
		}
	}
}

In un inizializzatore failable, quando il valore restituito è pari a zero indica che l’inizializzazione non è riuscita; nessun altro valore può essere restituito. Nell’esempio, il fallimento si verifica quando la stringa non può essere analizzata come un numero intero.  (essendo appunto un valore string e non int)

Ora, il compilatore Swift sintetizza un inizializzatore failable che prende un valore grezzo e tenta di associare ad uno dei casi enum. Per esempio:

enum Color : Int {
	case Red = 0, Green = 1, Blue = 2

	// implicitly synthesized
	var rawValue: Int { /* returns raw value for current case */ }

	// implicitly synthesized
	init?(rawValue: Int) {
		switch rawValue { 
			case 0: self = .Red
			case 1: self = .Green
			case 2: self = .Blue
			default: return nil
		}
	}
}

Utilizzando l’inizializzatore failable si semplifica la gestione degli errori, eliminando la confusione e le duplicazioni tra inizializzatori e metodi. Insieme con l’introduzione di initializers failable, Swift adesso supporta più metodi con argomenti NSError – come initializers, fornendo più alternative per la dichiarazione degli oggetti stessi.