DESIGN PATTERNS¶
Cosa imparerò:
- MVC
- MVVM
- Delegate
- Singleton
I design pattern sono soluzioni progettuali generali per problemi comuni nello sviluppo del software. Essi forniscono una struttura per organizzare il codice in modo efficiente, rendendo il software più mantenibile, comprensibile e estendibile. Nello sviluppo di app con Swift non esiste un solo pattern valido in assoluto: la scelta dipende dal tipo di progetto, dal framework utilizzato e dalla complessità dell’app.
Nelle applicazioni Apple, MVC è un pattern storico e centrale; inoltre, la delega è un pattern standard nelle API di sistema, mentre nei progetti SwiftUI è importante separare con chiarezza view, stato e dati osservabili.
Alcuni dei pattern più utili da conoscere nello sviluppo di app con Swift sono:
Model-View-Controller (MVC) Divide l'applicazione in tre componenti principali: Modello, View e Controller. - Il Modello gestisce i dati e la logica dell’app. - La View mostra le informazioni all’utente e raccoglie l’interazione. - Il Controller fa da ponte tra Modello e View, riceve gli input dell’utente, aggiorna i dati e decide come deve reagire l’interfaccia. Apple descrive MVC come un pattern in cui gli oggetti assumono uno dei tre ruoli di model, view o controller, separati da confini chiari e con responsabilità distinte; inoltre i view controller UIKit sono controller object che fanno da collegamento tra dati e interfaccia. Per esempio in una app per gestire una lista di film, il Model può essere Film; la View può essere una schermata con titolo, immagine e pulsanti; il Controller può essere un UIViewController che carica i film e aggiorna la schermata.
Separazione tra View, Model e logica di stato nei progetti SwiftUI Nei progetti SwiftUI moderni, più che parlare solo di MVC, conviene ragionare in termini di: - View: descrive l’interfaccia - Model: rappresenta i dati - Stato / logica di presentazione: gestisce i dati osservabili che fanno aggiornare la UI La documentazione Apple su SwiftUI e Observation mette al centro il flusso dei dati, lo stato locale, i modelli osservabili e l’aggiornamento automatico delle view quando i dati cambiano. Per esempio Nota è il modello dati; NoteView è la view; un oggetto osservabile, per esempio NoteStore, contiene l’elenco delle note e la logica per aggiungerle o rimuoverle
Delegate Il pattern Delegate permette a un oggetto di comunicare con un altro in modo flessibile, senza dover conoscere tutti i dettagli della sua implementazione. Apple descrive la delega come un pattern semplice e potente in cui un oggetto agisce per conto di un altro o in coordinamento con esso, inviando messaggi al delegate al momento opportuno. Nelle piattaforme Apple il delegate è ovunque. Alcuni esempi comuni sono UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate, CLLocationManagerDelegate.
Apple documenta, ad esempio, UITableViewDelegate come il protocollo che gestisce selezioni, intestazioni, eliminazione e altre azioni della tabella.
Come funziona - Un oggetto definisce un protocollo con alcuni metodi. - Un secondo oggetto adotta quel protocollo e diventa il suo delegate. - Quando accade un evento, il primo oggetto chiama il metodo del delegate.
Singleton Il pattern Singleton garantisce che esista una sola istanza di una classe e fornisce un punto di accesso condiviso a quell’istanza. È utile per oggetti che rappresentano risorse globali dell’app, come un gestore di configurazione, un logger o un servizio centralizzato.
Esempio Singleton
class DatabaseManager {
static let shared = DatabaseManager() // Singleton instance
private init() {} // Private initializer to prevent external instantiation
func connect() {
// Code to establish a database connection
print("Connected to the database")
}
func disconnect() {
// Code to close the database connection
print("Disconnected from the database")
}
// Other methods for interacting with the database
}
// Usage:
DatabaseManager.shared.connect()
In questo esempio, la classe DatabaseManager ha un'istanza statica condivisa (shared) che viene inizializzata una sola volta grazie al modificatore static let. Il costruttore è privato (private init()) per impedire la creazione di nuove istanze esterne. Grazie a ciò, ogni parte dell'applicazione che ha bisogno di accedere alla connessione al database può farlo utilizzando DatabaseManager.shared, garantendo che vi sia una sola istanza della classe per tutta l'applicazione.