Taylor-Swift-Interview

Questions pour préparer un entretien d’embauche pour un poste de développeur Swift

Après une longue période d’inactivité nous voilà enfin de retour avec une série d’article sur la préparation aux entretiens d’embauche (interview en anglais) en Swift. Comme chaque début d’année, c’est l’heure des nouvelles résolutions, et peut-être que certains d’entre vous souhaiterais changer d’orientation et / ou de poste pour se tourner vers le développement d’application Swift. Bien que Swift soit jeune, de nombreuses entreprises l’utilisent déjà et cherche donc des gens maitrisant ce langage. Dans cet article nous allons commencer par poser quelques questions, puis à y réponse ensuite de manière plus détailler.

Avant de commencer, nous tenons à préciser que ces questions portent sur le langage Swift 3.

Questions

Réponses

Quelle est la différence entre les mots clés var et let en Swift ?

Les mots clés var et let permettent tout les deux de déclarer une variable. Cependant let désigne une variable immuable (une constante) tandis que var permet de modifier la variable. Par example :

var arr1 = [1, 2, 3]
arr1.append(4)

let arr2 = [1, 2, 3]
arr2.append(4) // Cannot use mutating member on immutable value: 'arr2' is a let constant

Par contre des cas particuliers peuvent encore survenir en Swift 3 :

class MyClass {
  var number: Int = 0
}

let myClass    = MyClass()
myClass.number = 2 // cela fonctionne malgré la présence du mot clé let

Lorsque que l’on déclare un objet (et non une structure) avec le mot clé let on peut quand même modifier l’état interne de l’objet. En revanche on ne peut par ré-assigner la variable myClass.

(source: variable vs constante)

Qu’est ce que le type Optional ?

Le type optionnel (Optional) permet de définir l’absence de valeur en Swift. Il est définit en utilisant post-fixant le ? à la fin de la déclaration du type.

var monOptionnel: Int? = nil

if monOptionnel == nil {
}

// ou

if let value = monOptionnel {
  print(value)
}

Ici la variable monOptionnel peut soit contenir un nombre soit rien du tout (nil). On peut aussi trouver des Implicitly Unwrapped Optional Type qui sont des optionnels mais que l’on a pas besoin de tester :

var monOptionnel: Int! = 8

print(monOptionnel)

Mais il faut faire très attention à leur utilisation, car si ils sont vide votre programme va planter à l’exécution.

(source : le type optionnel)

Quel est la différence entre un type valeur et un type référence ?

Un type valeur (value type) en Swift est un type qui est passé par valeur (copié) lors d’un appel de fonction ou d’un assignement. Lorsqu’un type référence (reference type) est passé lors d’un appel de méthode ou d’un assignement on ne le copie pas, on propage sa référence :

// Type valeur
struct S { var data: Int = -1 }
var a = S()
var b = a                       // a est copié sur b
a.data = 42                     // change a, pas b
print("\(a.data), \(b.data)") // affiche "42, -1"

// Type référence
class C { var data: Int = -1 }
var x = C()
var y = x                       // y référence x
x.data = 42                     // les changements sur x affecte y
print("\(x.data), \(y.data)") // affiche "42, 42"

Pour faire simple en Swift les struct sont des types valeurs tandis que les class sont des types références.

Comment définir un opérateur personnalisé ?

Les nouveaux opérateurs doivent être déclaré globalement en utilisant le mot clé operator avec l’un des modificateurs suivant : prefix, infix ou postfix. Par example :

prefix operator +++

L’example du dessus définis un nouvel opérateur préfixé appelé +++. Pour qu’un objet puisse bénéficier de cet opérateur il faut ensuite implémenter la méthode statique static prefix func +++ (hs: inout T) -> TT désigne le type de l’objet. Par example avec un CGPoint :

extension CGPoint {
    static prefix func +++ (point: inout CGPoint) -> CGPoint {
        point.x += point.x
        point.y += point.y

        return point
    }
}

// Utilisation du nouvel opérateur
var p = CGPoint(x: 1, y: 1)
p     = +++p

(source: opérateurs personnalisés)

Qu’est qu’une extension ? Quelle est la différence entre l’extension et l’héritage ?

Les extensions permettent d’ajouter de nouvelle fonctionnalité à une classe, structure, énumération ou à un protocol existant. Cela permet d’étendre un type dont on a pas accès au code source original.

Les extensions permettent d’étendre l’API d’un objet existant sans en changer le type. Le subclassing permet aussi d’étendre les objets mais en introduisant un nouveau type. De plus l’héritage permet d’ajouter de nouvelle propriété.

Quels sont les moyens de faire de la programmation concurrente en Swift ?

Il y a 3 manières de faire de la programmation concurrente en Swift :

  • Les threads : Thread.
  • Grand Central Dispatch (GCD) : DispatchQueue.
  • Les operation queues : OperationQueue.

Quelle est la différence entre une méthode statique et une méthode de classe ?

La seule différence entre les 2 c’est qu’une méthode de classe peut être surchargé alors que qu’une méthode statique est considéré comme finale :

class MyClass {
  class func method1() {}
  static func method2() {}
}

class MySubClass: MyClass {
  // ok
  override class func method1() {}
  
  // error
  override static func method2() {}
}

Qu’est ce qu’une lazy collection et à quoi sert elle ?

Les collections et séquences paresseuses (lazy) sont identiques aux collections et séquences standards excepté que les fonctions de haut niveaux (map, reduce, filter) sont implémenté de manière paresseuse.

Cela permet d’économiser de la mémoire et du temps de calcul en faisant quelques optimisations. Dans ce premier example, au lieu d’appliquer la fonction sur l’ensemble des 1000 éléments on l’appel uniquement sur les éléments que l’on affiche :

let lazyArr = (1 ..< 1000).lazy.map { $0 * 2 }

print(lazyArr[3]) // affiche 6
print(lazyArr[50]) // affiche 100

Dans ce deuxième cas le runtime de Swift est capable de fusionner l’appel des 2 map en un seul :

let lazyArr = (1 ..< 1000).lazy.map({ $0 * 2 }).map({ $0 * 2 })

print(lazyArr[3]) // affiche 12
print(lazyArr[50]) // affiche 200

Qu’est ce qu’un cycle de rétention (retain cycle) et comment les éviter ?

Pour comprendre ce qu’est un cycle rétention en Swift il faut tout d’abord parler de l’ARC (Automatic Reference Counting). En Swift chaque objet possède un compteur de référence. Ce compteur vaut 1 lorsque que l’objet est créé, puis il est incrémenté chaque fois qu’un objet le référence (avec le modificateur strong) et il est décrémenté quand on le déférence. Une fois le compteur a 0, le runtime Swift le supprime de la mémoire.

Un cycle de rétention est une situation où un objet A possède une référence d’un objet B qui lui même contient une référence de l’objet A. Ceci à pour effet de créer un cycle « infini » où ni B, ni A ne seront supprimer de la mémoire. On appel aussi cette situation une fuite mémoire.

Pour éviter ce genre de situation, on peut utiliser le modificateur weak (ou unowned) sur une variable afin de ne pas incrémenter le compteur de référence :

weak var delegate: UITableViewDataSource?

Pour aller plus loin

Bien sûr il existe bien d’autre question possible sur le langage Swift. Pour approfondir votre maitrise du langage nous vous conseillons de lire au moins une fois en entier le guide fournis par Apple.

Dans des prochains articles nous nous intéresserons un peu plus aux question sur iOS et sur de l’algorithmique.

Si vous avez des remarques, des idées de question ou autre n’hésitez pas à laisser un commentaire juste au dessous.

1 Etoile2 Etoiles3 Etoiles4 Etoiles5 Etoiles (3 votes, average: 5,00 out of 5)
Loading...
Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInPin on PinterestShare on RedditDigg this

Aucun commentaire

Time limit is exhausted. Please reload CAPTCHA.