Chapitre 5
05 - iOS Natif
05 - iOS Natif
05 - iOS Natif : Cours complet
Table des matières
- Xcode : projet, schemes, signing
- Swift Package Manager et CocoaPods
- App lifecycle : scene et UIApplicationDelegate
- UIKit fundamentals
- Auto Layout et constraints
- GCD et OperationQueue
- Delegation et KVO
- Combine
- App Store : TestFlight et review
- Résumé et checklist
1. Xcode : projet, schemes, signing
1.1 Xcode
Xcode est l'IDE officiel d'Apple (macOS uniquement). Il comprend l'éditeur, le simulateur, les instruments (profiling), le debugger et le générateur d'UI (SwiftUI/Storyboard).
Composants clés :
- Projet (.xcodeproj) : contient targets, build settings, schemes.
- Workspace (.xcworkspace) : contient le projet + les packages pods.
- Target : une cible de build (app, extension, tests…).
- Scheme : définit quelles actions (Run/Test/Profile/Analyze/Archive) et quelle configuration utiliser.
1.2 Structure d'un projet
MyApp/
├── MyApp.xcodeproj
├── MyApp/
│ ├── MyAppApp.swift # @main, App entry (SwiftUI)
│ ├── ContentView.swift
│ ├── Assets.xcassets
│ ├── Info.plist
│ └── Preview Content/
├── MyAppTests/
├── MyAppUITests/
└── (SwiftPackage via File > Add Package Dependencies)
1.3 Schemes
Diagramme en cours de génération...
- Un scheme lie une target à des configurations (Debug/Release).
- Configs partagées dans le fichier
.xcscheme(à commiter). - On peut ajouter des actions de build pré/post (scripts).
1.4 Signing et provisioning
- Signing : signature de l'app avec un certificat (Developer ID, Apple Development, Distribution).
- Provisioning profile : associe l'app (Bundle ID) aux devices autorisés + entitlements (push, App Groups, etc.).
- Automatic signing : Xcode gère la plupart (nécessite un compte Apple ID/Developer).
- Manual signing : nécessaire pour les cas complexes (CI, app groups multiples).
Entitlements courants :
<!-- App.entitlements -->
<dict>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:example.com</string>
</array>
<key>aps-environment</key>
<string>development</string>
</dict>
1.5 Capabilities
On active les capacités dans Signing & Capabilities : Push, Background Modes, App Groups, Keychain Sharing, Associated Domains, In-App Purchase…
2. Swift Package Manager et CocoaPods
2.1 Swift Package Manager (SPM)
Le gestionnaire natif d'Apple, intégré à Xcode.
// Package.swift
// swift-tools-version: 6.0
import PackageDescription
let package = Package(
name: "MyApp",
platforms: [.iOS(.v17)],
dependencies: [
.package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.10.0"),
],
targets: [
.executableTarget(
name: "MyApp",
dependencies: ["Alamofire"]
)
]
)
Ajout dans Xcode : File → Add Package Dependencies… → URL ou search.
2.2 CocoaPods
Ancien standard, toujours utilisé par beaucoup d'équipes.
# Podfile
platform :ios, '17.0'
use_frameworks!
target 'MyApp' do
pod 'Alamofire', '~> 5.10'
end
pod install
open MyApp.xcworkspace
2.3 SPM vs CocoaPods
| Critère | SPM | CocoaPods |
|---|---|---|
| Intégration | Native Xcode | Workspace généré |
| Vitesse | Rapide | Moyenne |
| Écosystème | Jeune, en croissance | Mature |
| Apps dyn/static | Package | Pods |
| Recommandation 2026 | Par défaut | Héritage/maintenance |
3. App lifecycle : scene et UIApplicationDelegate
3.1 Architecture des scènes (iOS 13+)
UIApplicationDelegate: cycle de vie de l'app (lancement, liens, push).UISceneDelegate(ex.UIWindowSceneDelegate) : cycle de vie d'une scène (fenêtre).
Diagramme en cours de génération...
3.2 Étapes
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
return true
}
}
SwiftUI s'appuie sur AppDelegate seulement pour les intégrations (push, analytics). La vie de l'UI est gérée par la App :
@main
struct MyAppApp: App {
@Environment(\.scenePhase) private var scenePhase
var body: some Scene {
WindowGroup {
ContentView()
}
.onChange(of: scenePhase) { _, phase in
switch phase {
case .active: // reprendre
case .inactive: // transition
case .background: // sauvegarder
@unknown default: break
}
}
}
}
3.3 Règles
- Sauvegarder dans
scenePhase == .background. - Les tâches longues à la mise en arrière-plan :
beginBackgroundTaskouBGTaskScheduler. - Ne pas mettre à jour l'UI en
.background.
4. UIKit fundamentals
4.1 UIViewController
final class HomeViewController: UIViewController {
private let label = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
label.text = "Bonjour"
label.font = .preferredFont(forTextStyle: .headline)
view.addSubview(label)
}
}
Cycle : loadView → viewDidLoad → viewWillAppear → viewDidAppear → viewWillDisappear → viewDidDisappear → viewDidLoad (pop) → deinit.
4.2 UIView
- Toute hiérarchie d'UI :
UIView,UILabel,UIButton,UIImageView,UITableView,UICollectionView,UIScrollView… - Propriétés :
frame,bounds,center,transform,alpha,isHidden,tintColor.
4.3 Construire une UI programmatiquement
final class ProfileViewController: UIViewController {
private let avatar = UIImageView()
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
private func setupViews() {
view.addSubview(avatar)
avatar.translatesAutoresizingMaskIntoConstraints = false
avatar.layer.cornerRadius = 32
avatar.layer.masksToBounds = true
NSLayoutConstraint.activate([
avatar.widthAnchor.constraint(equalToConstant: 64),
avatar.heightAnchor.constraint(equalToConstant: 64),
avatar.centerXAnchor.constraint(equalTo: view.centerXAnchor),
avatar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 24),
])
}
}
4.4 Présentation de contrôleurs
let detail = DetailViewController()
detail.product = product
navigationController?.pushViewController(detail, animated: true) // empiler
present(detail, animated: true) // modal
5. Auto Layout et constraints
5.1 Principe
Auto Layout résout un système d'équations entre les vues, indépendant de la taille d'écran.
NSLayoutConstraint.activate([
titleLabel.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16),
titleLabel.trailingAnchor.constraint(lessThanOrEqualTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16),
titleLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 8),
])
5.2 Composantes
- Anchors : leading/trailing/top/bottom, width/height, centerX/centerY.
- Priorités :
required (1000),defaultHigh (750),defaultLow (250). - Contraintes intrinsèques : labels/boutons ont une taille par contenu (
contentHuggingPriority,contentCompressionResistancePriority).
5.3 Stack views
let stack = UIStackView(arrangedSubviews: [title, subtitle, button])
stack.axis = .vertical
stack.spacing = 12
stack.alignment = .fill
stack.distribution = .fill
5.4 Storyboards vs programmatique
| Critère | Storyboard | Programmatique |
|---|---|---|
| Visuel | Oui | Non |
| Merge/diff | Difficile | Facile |
| Reuse | Moyenne | Forte |
| Recommandation 2026 | Maintenance | Neuf + SwiftUI |
6. GCD et OperationQueue
6.1 GCD (Grand Central Dispatch)
// file background, retour sur le main
DispatchQueue.global(qos: .userInitiated).async {
let data = heavyCompute()
DispatchQueue.main.async {
self.updateUI(data)
}
}
QoS (Quality of Service) : .userInteractive, .userInitiated, .utility, .background. Plus la QoS est élevée, plus la priorité et la consommation énergie sont hautes.
6.2 DispatchQueue modernes
// async/await (recommandé pour le neuf)
Task {
let data = try await repository.fetch()
updateUI(data) // déjà sur MainActor
}
6.3 OperationQueue
Couche au-dessus de GCD : Operation + dépendances + annulation.
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 2
let download = BlockOperation { /* télécharger */ }
let process = BlockOperation { /* traiter */ }
process.addDependency(download)
queue.addOperations([download, process], waitUntilFinished: false)
6.4 Règles
- Ne jamais toucher l'UI hors du main thread.
- QoS adaptée au travail (
userInitiatedpour ce que l'utilisateur attend). - Annuler proprement les opérations ; vérifier
isCancelled.
7. Delegation et KVO
7.1 Delegation
Pattern central de UIKit : l'objet (data source/delegate) délégué reçoit des appels.
final class FeedViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
private var items: [String] = []
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = items[indexPath.row]
return cell
}
}
Protocoles de delegation : UITableViewDataSource, UITableViewDelegate, UICollectionViewDataSource…
7.2 KVO (Key-Value Observing)
Observation du changement d'une propriété Objective-C.
@objc dynamic var progress: Double = 0
// observateur
observe(\DownloadTask.progress, options: [.new]) { task, change in
print(change.newValue ?? 0)
}
KVO est peu utilisé en Swift moderne : Combine et Observation l'ont en grande partie remplacé.
7.3 Protocols & weak delegates
protocol PurchaseDelegate: AnyObject {
func didPurchase(product: Product)
}
final class PurchaseFlow {
weak var delegate: PurchaseDelegate? // weak pour éviter le cycle
}
8. Combine
8.1 Principe
Combine est le framework de programmation réactive d'Apple (iOS 13+) : Publisher, Subscriber, Operator.
import Combine
final class SearchViewModel: ObservableObject {
@Published var query = ""
@Published var results: [Product] = []
private var cancellables = Set<AnyCancellable>()
init(search: @escaping (String) async throws -> [Product]) {
$query
.debounce(for: .milliseconds(300), scheduler: RunLoop.main)
.removeDuplicates()
.sink { [weak self] q in
Task {
self?.results = try await search(q)
}
}
.store(in: &cancellables)
}
}
8.2 Opérateurs
map, filter, flatMap, combineLatest, zip, debounce, throttle, removeDuplicates, catch, receive(on:).
8.3 Sources
@Publishedsur unObservableObject.URLSession.dataTaskPublisher.NotificationCenter.default.publisher.Timer.publish.
8.4 Combine vs async/await
| Critère | Combine | async/await |
|---|---|---|
| Style | Réactif (flux) | Séquentiel |
| API publiques modernes | Moins | Plus (SwiftUI, URLSession) |
| Complexité | Élevée | Faible |
| Cas | Flux complexes, backpressure | La majorité du code |
Règle 2026 : async/await pour la logique, Combine (ou Observation) pour l'état observable, en conservant la compatibilité.
9. App Store : TestFlight et review
9.1 Le cycle de distribution
Diagramme en cours de génération...
9.2 TestFlight
- Jusqu'à 10 000 testeurs (90 jours par build).
- Interne : jusqu'à 100 membres de l'équipe (pas de review).
- Externe : jusqu'à 10 000 testeurs (review Basic pour la 1re version externe).
- Exporte les métadonnées (installations, sessions, crashs).
9.3 Review
- Guidelines 5.x (design), 3.x (business)… : à lire avant de soumettre.
- Délai typique 24–48 h ; litiges possibles.
- L'app doit être complète : pas de placeholders, pas d'accès révoqué.
- App Privacy : le nutrition label doit correspondre à ce que l'app collecte réellement.
9.4 Checklist de soumission
- Version et build incrementés
- Tests verts (unitaires + UI) sur device réel
- Privacy manifest + nutrition label à jour
- Screenshots pour toutes les tailles requises
- Vidéo d'aperçu (App Preview) si pertinent
- Compte démo/fonctionnalité de connexion pour le reviewer si besoin
- Rollout : manual or phased release
10. Résumé et checklist
10.1 Points clés
- Xcode : projets, targets, schemes, signing (automatique par défaut).
- SPM par défaut, CocoaPods en héritage.
- Scene lifecycle : ScenePhase (SwiftUI) ou sceneDelegate (UIKit).
- UIKit : UIViewController + UIView + Auto Layout.
- GCD/OperationQueue : concurrence ; async/await recommandé pour le neuf.
- Delegation partout en UIKit ; KVO remplacé par Observation/Combine.
- Combine : Publisher/Subscriber pour les flux.
- Distribution : Archive → TestFlight → Review → App Store.
10.2 Checklist
- Je crée un projet Xcode et je comprends targets/schemes
- Je configure le signing (automatique)
- J'ajoute une dépendance SPM
- Je gère le scenePhase de mon app
- Je construis une UI UIKit programmatique + Auto Layout
- J'exécute du travail en background avec GCD (QoS correcte)
- J'implémente un delegate weak
- Je crée un @Published + Combine pipeline
- Je soumets un build TestFlight
Prochain chapitre
→ 06-Swift : langage Swift moderne, async/await, actors, Codable, Swift 6.