• 12 hours
  • Hard

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 3/22/24

Refactorisez votre code

Normalement, vous devez vous sentir mal à l'aise. Votre code ne vous inspire pas confiance, mais vous ne savez pas trop pourquoi. Je vais vous aider. On a commis deux crimes majeurs :

  1. On a du code dupliqué entre les classes ListViewController  et SettingsViewController  .

  2. Surtout, on gère la sauvegarde/récupération de nos données directement dans le contrôleur. Or, la gestion des données, c'est côté modèle !

Maintenant que c'est dit, ne paniquons pas ! On va simplement refactoriser.

Ajoutons une nouvelle classe dans le modèle

Comme tout ça doit avoir lieu dans le modèle, on va créer un nouveau fichier SettingsRepository.swift  côté modèle, qui va contenir une classe du même nom :

// SettingsRepository.swift
class SettingsRepository {
}

Le rôle de cette classe va être de nous permettre de sauvegarder/récupérer notre monnaie depuis les UserDefaults. Pour cela, nous allons créer une propriété calculée currency  :

final class SettingsRepository {
   var currency: String {
      get {
      }
      set {
      }
   }
}

Nous allons maintenant modifier le getter et le setter. Le getter va nous permettre de récupérer notre monnaie depuis les UserDefaults. Et le setter va nous permettre de la sauvegarder :

var currency: String {
   get {
      return UserDefaults.standard.string(forKey: "currency") ?? "€"
   }
   set {
      UserDefaults.standard.set(newValue, forKey: "currency")
   }
}

Et voilà ! Maintenant, on a une propriété currency  très simple à utiliser, et qui fait pour nous tout le travail de sauvegarder/récupérer notre donnée depuis les UserDefaults.

Malgré l'élégance de notre code, nous répétons encore un élément : notre clé currency. Je vous propose du coup qu'on factorise encore cela avec une  enum Keys   qui pourra contenir toutes les clés dont nous avons besoin :

class SettingsRepository {
   private enum Keys {
      static let currency = "currency"
   }
   static var currency: String {
      get {
         return UserDefaults.standard.string(forKey: Keys.currency) ?? "€"
      }
      set {
         UserDefaults.standard.set(newValue, forKey: Keys.currency)
      }
   }
}

Là ça commence à me plaire ! C'est bien beau !

On se fait plaisir...

Maintenant, on peut se faire plaisir en utilisant notre classe à la place des différents endroits où on utilisait UserDefaults directement dans notre contrôleur :

// SettingsViewController.swift
final class SettingsViewController: UIViewController {
    // MARK: - Properties
    private let settingsRepository = SettingsRepository()
    // MARK: - Outlets
    @IBOutlet private weak var currencyLabel: UILabel!
    // MARK: - View life cycle
    override func viewDidLoad() {
        super.viewDidLoad()
        currencyLabel.text = settingsRepository.currency
    }
    // MARK: - Actions
    @IBAction private func dismiss() {
        dismiss(animated: true, completion: nil)
    }
    @IBAction private func changeCurrency(_ sender: UIButton) {
        guard let currency = sender.titleLabel?.text else { return }
        currencyLabel.text = currency
        settingsRepository.currency = currency
    }
}
}

// ListViewController.swift
final class ListViewController: UIViewController {
    // MARK: - Properties
    private let spendingRepository = SpendingRepository()
    private let settingsRepository = SettingsRepository()
    private var spendings: [Spending] = []

    // MARK: - Outlets

    @IBOutlet private weak var tableView: UITableView!
    // MARK: - View life cycle

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        spendings = spendingRepository.spendings
        tableView.reloadData()
    }
}

extension ListViewController: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return spendings.count
    }

        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "SpendingCell", for: indexPath)

        let spending = spendings[indexPath.row]
        cell.textLabel?.text = spending.content
            cell.detailTextLabel?.text = "\(spending.amount) \(settingsRepository.currency)"

        return cell
    }
}

Là normalement, vous devez ressentir des petits papillons dans le ventre, ou vous n'avez pas de cœur !

En résumé

  • UserDefaults est la technique de persistance la plus simple et la plus rapide à mettre en place. Et elle rend bien des services !

  • Elle n'est adaptée qu'à des données très basiques et réduites.

  • La sauvegarde et la récupération des données sont gérées dans le modèle. 

  • On factorise notre code pour éviter la répétition d'éléments. 

Aussi, si vous voulez mettre en place une stratégie de persistance efficace dans votre application, il vous faut prendre en main au moins une autre technique. Et c'est ce que nous allons faire dans les deux prochaines parties avec Core Data !

Example of certificate of achievement
Example of certificate of achievement