Non perdere mai un post

Ti ritrovi mai a desiderare che Apple includesse un inizializzatore extra in una classe UIKit? Le estensioni Swift semplificano l’aggiunta di nuovi inizializzatori ai tipi senza sottoclassi. Le mie note rapide sull’aggiunta di un nuovo inizializzatore di convenienza a una classe UIKit utilizzando un’estensione Swift.

Designato o Convenienza?

Prima un riepilogo sui due tipi di inizializzatore:

Un inizializzatore designato è l’inizializzatore primario per una classe. Deve inizializzare completamente tutte le proprietà introdotte dalla sua classe prima di chiamare un inizializzatore superclasse. Una classe può avere più di un inizializzatore designato.

Un inizializzatore di convenienza è un inizializzatore secondario che deve chiamare un inizializzatore designato della stessa classe. È utile quando si desidera fornire valori predefiniti o altre impostazioni personalizzate. Una classe non richiede inizializzatori convenienza.

Le tre regole

Con questo chiaro è necessario ricordare tre regole per gli inizializzatori designati e di convenienza per i tipi di classe:

  • Un inizializzatore designato deve chiamare un inizializzatore designato dalla superclasse immediata.
  • Un inizializzatore di convenienza deve chiamare un altro inizializzatore dalla stessa classe.
  • Un inizializzatore di convenienza deve in ultima analisi chiamare un inizializzatore designato.

Cosa significa per noi? In termini semplici, non chiamare super dal tuo inizializzatore di convenienza. Chiama un altro inizializzatore (convenienza o designato) dalla stessa classe.

Un esempio pratico

Proviamo con un esempio pratico. La creazione e la configurazione di una vista immagine da un’immagine nel catalogo risorse pronta per l’uso con Layout automatico richiede diverse righe di codice:

// Create the imagelet heartImage = UIImage(named: "Heart")// Now create the image view using the imagelet heartImageView = UIImageView(image: heartImage)// Configure the view remembering to disable// the autoresizing mask if we are using// Auto LayoutheartImageView.translatesAutoresizingMaskIntoConstraints = false// Sometime we must also override the default content modeheartImageView.contentMode = .scaleAspectFit// Finally add to the view hierarchyview.addSubview(heartImageView)

Questo diventa noioso rapidamente e finisco sempre per dimenticare di disabilitare la traduzione della maschera di ridimensionamento automatico.

Creazione di un inizializzatore di convenienza

Creiamo un nuovo UIImageView inizializzatore di convenienza che esegue la configurazione per noi. Il nostro inizializzatore prenderà il nome dell’immagine nel catalogo delle risorse e la modalità contenuto. Dal momento che non sempre vogliamo impostare la modalità di contenuto faremo di default per scalare per riempire. Ecco il codice:

extension UIImageView { convenience init?(named name: String, contentMode: UIViewContentMode = .scaleToFill) { guard let image = UIImage(named: name) else { return nil } self.init(image: image) self.contentMode = contentMode translatesAutoresizingMaskIntoConstraints = false }}

Alcuni punti da notare:

  • Se il parametro nome immagine non è valido, il nostro inizializzatore fallirà e dovrebbe restituire nil. Si definisce un inizializzatore fallibile con un punto interrogativo dopo la parola chiave init(init?).
  • Una volta che abbiamo un UIImage valido chiamiamo l’inizializzatore designato di UIImageView per creare la vista immagine.
  • Possiamo impostare le proprietà sull’oggetto UIImageView solo dopo aver chiamato l’inizializzatore designato.

Esempio di utilizzo

// Default contentModelet heart = UIImageView(named: "Heart")// Specifying a contentModelet star = UIImageView(named: "Star", contentMode: .scaleAspectFit)

Si noti che l’inizializzatore failable significa che il tipo di ritorno è facoltativo (UIImageView?) quindi avremmo bisogno di scartarlo prima di aggiungerlo alla superview.

Accesso alle proprietà Prima di inizializzare Self

Un’ultima nota su quando è possibile accedere self per modificare le proprietà. Se proviamo a impostare una proprietà di UIImageView prima di aver chiamato self.init(image: UIImage?) otteniamo un errore:

// Does not compileself.contentMode = contentModeself.init(image: image)// Use of 'self' in property access 'contentMode'// before self.init initializes self

Se ricordi che un inizializzatore designato deve inizializzare completamente tutte le proprietà della sua classe, puoi forse capire perché questo non è permesso. Anche se il compilatore ci permettesse di farlo, l’inizializzatore designato sovrascriverebbe il nostro valore con il valore predefinito.

Ulteriori letture

Le sezioni sull’inizializzazione e le estensioni nella guida al linguaggio di programmazione Swift hanno molti più dettagli:

  • Inizializzazione
  • Estensioni

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.