Ne manquez jamais un post

Vous êtes-vous déjà trouvé à souhaiter qu’Apple inclue un initialiseur supplémentaire dans une classe UIKit? Les extensions Swift facilitent l’ajout de nouveaux initialiseurs aux types sans sous-classe. Mes notes rapides sur l’ajout d’un nouvel initialiseur pratique à une classe UIKit à l’aide d’une extension Swift.

Désigné ou pratique?

Tout d’abord un récapitulatif sur les deux types d’initialiseur :

Un initialiseur désigné est l’initialiseur principal d’une classe. Il doit initialiser complètement toutes les propriétés introduites par sa classe avant d’appeler un initialiseur de superclasse. Une classe peut avoir plus d’un initialiseur désigné.

Un initialiseur de commodité est un initialiseur secondaire qui doit appeler un initialiseur désigné de la même classe. Il est utile lorsque vous souhaitez fournir des valeurs par défaut ou une autre configuration personnalisée. Une classe ne nécessite pas d’initialiseurs de commodité.

Les trois règles

Avec cela clair, vous devez vous souvenir de trois règles pour les initialiseurs désignés et pratiques pour les types de classe:

  • Un initialiseur désigné doit appeler un initialiseur désigné de la superclasse immédiate.
  • Un initialiseur de commodité doit appeler un autre initialiseur de la même classe.
  • Un initialiseur de commodité doit finalement appeler un initialiseur désigné.

Qu’est-ce que cela signifie pour nous? En termes simples, n’appelez pas super depuis votre initialiseur de commodité. Appelez un autre initialiseur (commodité ou désigné) de la même classe.

Un exemple pratique

Essayons avec un exemple pratique. La création et la configuration d’une vue d’image à partir d’une image du catalogue d’actifs prête à être utilisée avec la mise en page automatique nécessitent plusieurs lignes de code:

// 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)

Cela devient vite ennuyeux et je finis toujours par oublier de désactiver la traduction du masque de redimensionnement automatique.

Création d’un initialiseur de commodité

Créons un nouvel initialiseur de commodité UIImageView qui effectue la configuration pour nous. Notre initialiseur prendra le nom de l’image dans le catalogue d’actifs et le mode contenu. Comme nous ne voulons pas toujours définir le mode de contenu, nous le mettrons par défaut à l’échelle pour remplir. Voici le code:

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 }}

Quelques points à noter:

  • Si le paramètre nom de l’image n’est pas valide, notre initialiseur échouera et devrait renvoyer nil. Vous définissez un initialiseur échouable avec un point d’interrogation après le mot-clé init (init?).
  • Une fois que nous avons un UIImage valide, nous appelons l’initialiseur désigné de UIImageView pour créer la vue d’image.
  • Nous ne pouvons définir des propriétés sur l’objet UIImageView qu’après avoir appelé l’initialiseur désigné.

Exemple d’utilisation

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

Notez que l’initialiseur échouable signifie que le type de retour est facultatif (UIImageView?) nous aurions donc besoin de le déballer avant de l’ajouter à la vue d’ensemble.

Accès aux propriétés Avant d’initialiser Self

Une dernière note sur le moment où vous pouvez accéder à self pour modifier les propriétés. Si nous essayons de définir une propriété de UIImageView avant d’avoir appelé self.init(image: UIImage?), nous obtenons une erreur:

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

Si vous vous souvenez qu’un initialiseur désigné doit initialiser complètement toutes les propriétés de sa classe, vous pouvez peut-être voir pourquoi cela n’est pas autorisé. Même si le compilateur nous permettait de le faire, l’initialiseur désigné écraserait notre valeur par la valeur par défaut.

Lectures supplémentaires

Les sections sur l’initialisation et les extensions du guide du langage de programmation Swift contiennent beaucoup plus de détails:

  • Initialisation
  • Extensions

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.