décembre 21, 2025
14 min de lecture

Questions d'entretien pour développeur mobile junior (iOS) : Guide complet

interview
career-advice
job-search
entry-level
Questions d'entretien pour développeur mobile junior (iOS) : Guide complet
MB

Milad Bonakdar

Auteur

Maîtrisez les fondamentaux du développement iOS avec des questions d'entretien essentielles couvrant Swift, UIKit, SwiftUI, la persistance des données et l'architecture des applications iOS pour les développeurs juniors.


Introduction

Le développement iOS est devenu l'une des compétences les plus recherchées dans le développement d'applications mobiles. Avec Swift comme langage principal et des frameworks puissants comme UIKit et SwiftUI, les développeurs iOS créent des expériences pour des millions d'utilisateurs dans le monde entier.

Ce guide couvre les questions d'entretien essentielles pour les développeurs iOS débutants. Nous explorons les fondamentaux de Swift, le développement d'interfaces utilisateur, la persistance des données, la mise en réseau et les meilleures pratiques iOS pour vous aider à vous préparer à votre premier rôle de développeur iOS.


Fondamentaux de Swift (6 Questions)

1. Quelle est la différence entre var et let en Swift ?

Réponse :

  • var : Déclare une variable mutable. Sa valeur peut être modifiée après l'initialisation.
  • let : Déclare une constante immuable. Une fois définie, sa valeur ne peut plus être modifiée.
  • Bonne pratique : Utilisez let par défaut pour la sécurité et la clarté. N'utilisez var que lorsque vous savez que la valeur changera.
let name = "John"  // Ne peut pas être changé
var age = 25       // Peut être changé
age = 26           // Valide
// name = "Jane"   // Erreur : Impossible d'assigner une valeur

Rareté : Très courant Difficulté : Facile


2. Expliquez les Optionnels en Swift. Qu'est-ce que le "Optional Binding" ?

Réponse : Les optionnels représentent une valeur qui peut être nil (absence de valeur).

  • Déclaration : Utilisez ? après le type : var name: String?
  • Méthodes de déballage :
    • Déballage forcé : name! (dangereux, plante si nil)
    • Optional Binding : Déballage sécurisé en utilisant if let ou guard let
    • Nil Coalescing : name ?? "Default"
    • Optional Chaining : user?.address?.city
var email: String? = "[email protected]"

// Optional Binding
if let unwrappedEmail = email {
    print("Email: \(unwrappedEmail)")
} else {
    print("Pas d'email")
}

// Instruction Guard
guard let email = email else { return }
print(email)

Rareté : Très courant Difficulté : Facile


3. Quelle est la différence entre une class et une struct en Swift ?

Réponse :

  • Class : Type de référence (stocké sur le tas). Prend en charge l'héritage. Passé par référence.
  • Struct : Type de valeur (stocké sur la pile). Pas d'héritage. Passé par copie.
  • Quand utiliser :
    • Struct : Pour les modèles de données simples, lorsque vous voulez une sémantique de valeur (copies indépendantes)
    • Class : Lorsque vous avez besoin d'héritage, de sémantique de référence ou de désinitialiseurs
struct Point {
    var x: Int
    var y: Int
}

class Person {
    var name: String
    init(name: String) { self.name = name }
}

var p1 = Point(x: 0, y: 0)
var p2 = p1  // Copie créée
p2.x = 10    // p1.x est toujours 0

var person1 = Person(name: "John")
var person2 = person1  // Même référence
person2.name = "Jane"  // person1.name est aussi "Jane"

Rareté : Très courant Difficulté : Moyenne


4. Que sont les Closures en Swift ?

Réponse : Les closures sont des blocs de fonctionnalités autonomes qui peuvent être transmis et utilisés dans votre code. Elles sont similaires aux lambdas ou aux fonctions anonymes dans d'autres langages.

  • Syntaxe : { (parameters) -> ReturnType in statements }
  • Capture de valeurs : Les closures peuvent capturer et stocker des références aux variables de leur contexte environnant.
  • Utilisation courante : Gestionnaires de complétion, rappels, opérations de tableau.
// Closure simple
let greet = { (name: String) -> String in
    return "Bonjour, \(name) !"
}
print(greet("Alice"))

// Syntaxe de closure de fuite
let numbers = [1, 2, 3, 4, 5]
let doubled = numbers.map { $0 * 2 }
print(doubled)  // [2, 4, 6, 8, 10]

Rareté : Très courant Difficulté : Moyenne


5. Expliquez la différence entre les références weak et unowned.

Réponse : Les deux sont utilisés pour empêcher les cycles de rétention (fuites de mémoire) dans les types de référence.

  • weak : Référence optionnelle qui devient automatiquement nil lorsque l'objet référencé est désalloué. Utilisez-la lorsque la référence pourrait survivre à l'objet.
  • unowned : Référence non optionnelle qui suppose que l'objet existera toujours. Plante si elle est accédée après la désallocation. Utilisez-la lorsque vous êtes certain que la référence ne survivra pas à l'objet.
class Person {
    var name: String
    weak var apartment: Apartment?  // weak pour empêcher le cycle de rétention
    init(name: String) { self.name = name }
}

class Apartment {
    var unit: String
    unowned let tenant: Person  // unowned - l'appartement a toujours un locataire
    init(unit: String, tenant: Person) {
        self.unit = unit
        self.tenant = tenant
    }
}

Rareté : Courant Difficulté : Moyenne


6. Que sont les Protocoles en Swift ?

Réponse : Les protocoles définissent un modèle de méthodes, de propriétés et d'autres exigences qui conviennent à une tâche ou à une fonctionnalité particulière. Les classes, les structures et les énumérations peuvent adopter des protocoles.

  • Similaire à : Les interfaces dans d'autres langages
  • Extensions de protocole : Peut fournir des implémentations par défaut
  • Programmation orientée protocole : Le paradigme préféré de Swift
protocol Drawable {
    func draw()
}

struct Circle: Drawable {
    var radius: Double
    
    func draw() {
        print("Dessin d'un cercle avec un rayon de \(radius)")
    }
}

struct Rectangle: Drawable {
    var width: Double
    var height: Double
    
    func draw() {
        print("Dessin d'un rectangle de \(width)x\(height)")
    }
}

Rareté : Très courant Difficulté : Facile


Bases de UIKit (5 Questions)

7. Quelle est la différence entre UIView et UIViewController ?

Réponse :

  • UIView : Représente une zone rectangulaire à l'écran. Gère le dessin et la gestion des événements. Exemples : UILabel, UIButton, UIImageView.
  • UIViewController : Gère une hiérarchie de vues. Gère le cycle de vie de la vue, les interactions de l'utilisateur et la navigation. Contient une vue racine et gère ses sous-vues.
  • Relation : Un contrôleur de vue gère les vues. Un contrôleur de vue peut avoir de nombreuses vues.

Rareté : Très courant Difficulté : Facile


8. Expliquez les méthodes du cycle de vie du contrôleur de vue.

Réponse : Les contrôleurs de vue ont des méthodes de cycle de vie spécifiques appelées dans l'ordre :

  1. viewDidLoad() : Appelé une fois lorsque la vue est chargée en mémoire. Configuration qui doit avoir lieu une seule fois.
  2. viewWillAppear(_:) : Appelé avant que la vue n'apparaisse à l'écran. Peut être appelé plusieurs fois.
  3. viewDidAppear(_:) : Appelé après que la vue est apparue à l'écran. Démarrez les animations ici.
  4. viewWillDisappear(_:) : Appelé avant que la vue ne disparaisse.
  5. viewDidDisappear(_:) : Appelé après que la vue a disparu. Nettoyez les ressources.
override func viewDidLoad() {
    super.viewDidLoad()
    // Configuration unique : configurer l'interface utilisateur, charger les données
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    // Actualiser les données, commencer à écouter les notifications
}

Rareté : Très courant Difficulté : Facile


9. Qu'est-ce que l'Auto Layout et comment utilisez-vous les contraintes ?

Réponse : L'Auto Layout est un système de mise en page basé sur des contraintes qui vous permet de créer des interfaces utilisateur adaptatives qui fonctionnent sur différentes tailles d'écran et orientations.

  • Contraintes : Définissent les relations entre les vues (largeur, hauteur, espacement, alignement)
  • Méthodes :
    • Interface Builder : Éditeur visuel dans Xcode
    • Programmatic : API NSLayoutConstraint ou NSLayoutAnchor
    • Visual Format Language : Basé sur des chaînes (moins courant maintenant)
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)

NSLayoutConstraint.activate([
    button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
    button.centerYAnchor.constraint(equalTo: view.centerYAnchor),
    button.widthAnchor.constraint(equalToConstant: 200),
    button.heightAnchor.constraint(equalToConstant: 50)
])

Rareté : Très courant Difficulté : Moyenne


10. Quelle est la différence entre frame et bounds ?

Réponse :

  • frame : L'emplacement et la taille de la vue dans le système de coordonnées de sa supervue. Utilisé pour positionner la vue.
  • bounds : L'emplacement et la taille de la vue dans son propre système de coordonnées. L'origine est généralement (0, 0). Utilisé pour dessiner du contenu à l'intérieur de la vue.
  • Différence clé : frame est relatif au parent, bounds est relatif à lui-même.
let view = UIView(frame: CGRect(x: 50, y: 100, width: 200, height: 150))
print(view.frame)   // (50, 100, 200, 150) - position dans la supervue
print(view.bounds)  // (0, 0, 200, 150) - propre système de coordonnées

Rareté : Courant Difficulté : Moyenne


11. Comment gérez-vous la saisie de l'utilisateur à partir d'un UITextField ?

Réponse : Plusieurs approches existent :

  • Target-Action : Ajouter une cible pour l'événement .editingChanged
  • Delegate : Se conformer au protocole UITextFieldDelegate
  • Combine : Utiliser des éditeurs (approche moderne)
class ViewController: UIViewController, UITextFieldDelegate {
    let textField = UITextField()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Approche Delegate
        textField.delegate = self
        
        // Approche Target-Action
        textField.addTarget(self, action: #selector(textChanged), for: .editingChanged)
    }
    
    @objc func textChanged(_ textField: UITextField) {
        print("Texte : \(textField.text ?? "")")
    }
    
    // Méthode Delegate
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }
}

Rareté : Très courant Difficulté : Facile


Bases de SwiftUI (4 Questions)

12. Qu'est-ce que SwiftUI et en quoi est-il différent de UIKit ?

Réponse : SwiftUI est le framework d'interface utilisateur déclaratif d'Apple introduit dans iOS 13.

  • UIKit : Impératif (vous dites au système comment construire l'interface utilisateur étape par étape). Mature, largement utilisé.
  • SwiftUI : Déclaratif (vous décrivez à quoi devrait ressembler l'interface utilisateur). Moderne, moins de code, mises à jour automatiques.
  • Principales caractéristiques :
    • Aperçu en direct dans Xcode
    • Multiplateforme (iOS, macOS, watchOS, tvOS)
    • Mises à jour de l'interface utilisateur basées sur l'état
    • Animations intégrées
// SwiftUI
struct ContentView: View {
    @State private var count = 0
    
    var body: some View {
        VStack {
            Text("Compteur : \(count)")
            Button("Incrémenter") {
                count += 1
            }
        }
    }
}

Rareté : Très courant Difficulté : Facile


13. Expliquez @State, @Binding et @ObservedObject dans SwiftUI.

Réponse : Ce sont des wrappers de propriétés pour gérer l'état dans SwiftUI :

  • @State : État privé possédé par la vue. Lorsqu'il change, la vue est rendue à nouveau.
  • @Binding : Crée une connexion bidirectionnelle à une propriété @State appartenant à une vue parente.
  • @ObservedObject : Référence un objet externe (classe se conformant à ObservableObject). La vue se met à jour lorsque les propriétés @Published de l'objet changent.
class UserData: ObservableObject {
    @Published var name = ""
}

struct ParentView: View {
    @State private var isOn = false
    @ObservedObject var userData = UserData()
    
    var body: some View {
        VStack {
            ChildView(isOn: $isOn)  // Passer la liaison
            Text(userData.name)
        }
    }
}

struct ChildView: View {
    @Binding var isOn: Bool  // Reçoit la liaison
    
    var body: some View {
        Toggle("Switch", isOn: $isOn)
    }
}

Rareté : Courant Difficulté : Moyenne


14. Comment créez-vous une liste dans SwiftUI ?

Réponse : Utilisez la vue List pour afficher des collections de données défilables.

struct ContentView: View {
    let fruits = ["Apple", "Banana", "Orange", "Grape"]
    
    var body: some View {
        List(fruits, id: \.self) { fruit in
            Text(fruit)
        }
    }
}

// Avec un modèle personnalisé
struct Task: Identifiable {
    let id = UUID()
    let title: String
}

struct TaskListView: View {
    let tasks = [
        Task(title: "Buy groceries"),
        Task(title: "Walk the dog")
    ]
    
    var body: some View {
        List(tasks) { task in
            Text(task.title)
        }
    }
}

Rareté : Courant Difficulté : Facile


15. Que sont les Modificateurs de Vue dans SwiftUI ?

Réponse : Les modificateurs de vue sont des méthodes qui créent une nouvelle vue avec des propriétés modifiées. Ils sont chaînables.

  • Modificateurs courants : .padding(), .background(), .foregroundColor(), .font(), .frame()
  • L'ordre compte : Les modificateurs sont appliqués en séquence
Text("Hello, World!")
    .font(.title)
    .foregroundColor(.blue)
    .padding()
    .background(Color.yellow)
    .cornerRadius(10)
    .shadow(radius: 5)

// Modificateur personnalisé
struct PrimaryButtonStyle: ViewModifier {
    func body(content: Content) -> some View {
        content
            .padding()
            .background(Color.blue)
            .foregroundColor(.white)
            .cornerRadius(8)
    }
}

extension View {
    func primaryButton() -> some View {
        modifier(PrimaryButtonStyle())
    }
}

Rareté : Courant Difficulté : Facile


Données et Réseau (5 Questions)

16. Comment faites-vous une requête réseau dans iOS ?

Réponse : Utilisez URLSession pour les tâches de mise en réseau.

func fetchData() {
    guard let url = URL(string: "https://api.example.com/data") else { return }
    
    let task = URLSession.shared.dataTask(with: url) { data, response, error in
        if let error = error {
            print("Erreur : \(error)")
            return
        }
        
        guard let data = data else { return }
        
        // Analyser JSON
        do {
            let decoder = JSONDecoder()
            let result = try decoder.decode(MyModel.self, from: data)
            print(result)
        } catch {
            print("Erreur de décodage : \(error)")
        }
    }
    
    task.resume()
}

Rareté : Très courant Difficulté : Moyenne


17. Qu'est-ce que Codable en Swift ?

Réponse : Codable est un alias de type pour les protocoles Encodable & Decodable. Il permet une conversion facile entre les types Swift et les représentations externes comme JSON.

  • Synthèse automatique : Swift génère automatiquement le code d'encodage/décodage si toutes les propriétés sont Codable.
  • Clés personnalisées : Utilisez l'énumération CodingKeys pour mapper différents noms de propriétés.
struct User: Codable {
    let id: Int
    let name: String
    let email: String
}

// Décodage JSON
let json = """
{
    "id": 1,
    "name": "John Doe",
    "email": "[email protected]"
}
""".data(using: .utf8)!

let decoder = JSONDecoder()
let user = try decoder.decode(User.self, from: json)

// Encodage vers JSON
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let jsonData = try encoder.encode(user)

Rareté : Très courant Difficulté : Facile


18. Comment persistez-vous les données localement dans iOS ?

Réponse : Plusieurs options pour la persistance des données locales :

  • UserDefaults : Stockage clé-valeur simple pour de petites quantités de données (paramètres, préférences)
  • Système de fichiers : Enregistrer les fichiers dans le répertoire Documents ou Cache
  • Core Data : Le framework d'Apple pour la gestion et la persistance des graphes d'objets
  • SQLite : Base de données relationnelle
  • Keychain : Stockage sécurisé pour les données sensibles (mots de passe, jetons)
// UserDefaults
UserDefaults.standard.set("John", forKey: "username")
let username = UserDefaults.standard.string(forKey: "username")

// Système de fichiers
let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let filePath = documentsPath.appendingPathComponent("data.json")

// Écrire
try data.write(to: filePath)

// Lire
let loadedData = try Data(contentsOf: filePath)

Rareté : Très courant Difficulté : Facile


19. Quelle est la différence entre les opérations synchrones et asynchrones ?

Réponse :

  • Synchrone : Bloque le thread courant jusqu'à ce que l'opération soit terminée. Peut geler l'interface utilisateur si elle est exécutée sur le thread principal.
  • Asynchrone : Ne bloque pas le thread. L'opération s'exécute en arrière-plan, et un gestionnaire de complétion est appelé une fois terminée.
  • Thread principal : Les mises à jour de l'interface utilisateur doivent se produire sur le thread principal. Utilisez DispatchQueue.main.async pour passer au thread principal.
// Synchrone (MAUVAIS pour les appels réseau)
let data = try Data(contentsOf: url)  // Bloque jusqu'à la fin

// Asynchrone (BON)
URLSession.shared.dataTask(with: url) { data, response, error in
    // Ceci s'exécute sur un thread d'arrière-plan
    
    DispatchQueue.main.async {
        // Mettre à jour l'interface utilisateur sur le thread principal
        self.label.text = "Données chargées"
    }
}.resume()

Rareté : Courant Difficulté : Facile


20. Qu'est-ce que Grand Central Dispatch (GCD) ?

Réponse : GCD est l'API de bas niveau d'Apple pour la gestion des opérations concurrentes.

  • Dispatch Queues : Files d'attente FIFO qui exécutent des tâches en série ou en concurrence
  • Main Queue : File d'attente série pour les mises à jour de l'interface utilisateur
  • Global Queues : Files d'attente concurrentes avec différentes priorités (arrière-plan, utilitaire, initié par l'utilisateur)
// Exécuter sur un thread d'arrière-plan
DispatchQueue.global(qos: .background).async {
    // Calcul lourd
    let result = performExpensiveOperation()
    
    // Mettre à jour l'interface utilisateur sur le thread principal
    DispatchQueue.main.async {
        self.label.text = result
    }
}

// Retarder l'exécution
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
    print("Exécuté après 2 secondes")
}

Rareté : Courant Difficulté : Moyenne


Newsletter subscription

Conseils de carrière hebdomadaires qui fonctionnent vraiment

Recevez les dernières idées directement dans votre boîte de réception

Decorative doodle

Démarquez-vous auprès des Recruteurs et Décrochez Votre Emploi de Rêve

Rejoignez des milliers de personnes qui ont transformé leur carrière avec des CV alimentés par l'IA qui passent les ATS et impressionnent les responsables du recrutement.

Commencer maintenant

Partager cet article

Faites Compter Vos 6 Secondes

Les recruteurs scannent les CV pendant seulement 6 à 7 secondes en moyenne. Nos modèles éprouvés sont conçus pour capter l'attention instantanément et les inciter à continuer la lecture.