La concurrència és un concepte fonamental en la programació moderna que permet executar múltiples tasques al mateix temps, millorant així l'eficiència i la resposta de les aplicacions. En Swift, la concurrència es gestiona principalment mitjançant Grand Central Dispatch (GCD) i operacions. Aquest mòdul t'introduirà als conceptes bàsics de la concurrència en Swift i et mostrarà com utilitzar-los en les teves aplicacions.
Objectius d'Aprenentatge
- Comprendre els conceptes bàsics de la concurrència.
- Aprendre a utilitzar Grand Central Dispatch (GCD) per gestionar tasques concurrents.
- Utilitzar operacions per gestionar tasques concurrents de manera més controlada.
- Implementar concurrència segura per evitar condicions de carrera i altres problemes comuns.
Conceptes Bàsics de la Concurrència
Què és la Concurrència?
La concurrència permet que múltiples tasques es realitzin al mateix temps. Això és especialment útil en aplicacions que necessiten realitzar operacions intensives en temps, com ara descàrregues de xarxa, processament d'imatges o càlculs complexos, sense bloquejar la interfície d'usuari.
Multithreading
El multithreading és una tècnica de programació que permet executar múltiples fils (threads) dins d'un mateix procés. Cada fil pot executar una tasca diferent de manera concurrent.
Grand Central Dispatch (GCD)
GCD és una tecnologia d'Apple que facilita la gestió de tasques concurrents. GCD utilitza cues (queues) per gestionar l'execució de tasques de manera eficient.
Utilitzant Grand Central Dispatch (GCD)
Cues (Queues)
GCD utilitza cues per gestionar l'execució de tasques. Hi ha dos tipus principals de cues:
- Cues Serials: Executen una tasca a la vegada en l'ordre en què es van afegir.
- Cues Concurrent: Permeten l'execució de múltiples tasques al mateix temps.
Exemple de Cues Serials
let serialQueue = DispatchQueue(label: "com.example.serialQueue") serialQueue.async { print("Tasca 1") } serialQueue.async { print("Tasca 2") }
Exemple de Cues Concurrent
let concurrentQueue = DispatchQueue(label: "com.example.concurrentQueue", attributes: .concurrent) concurrentQueue.async { print("Tasca 1") } concurrentQueue.async { print("Tasca 2") }
Tasques Asíncrones i Síncrones
- Asíncrones (async): Les tasques s'executen en segon pla i el control retorna immediatament.
- Síncrones (sync): Les tasques s'executen i el control no retorna fins que la tasca ha finalitzat.
Exemple de Tasca Asíncrona
Exemple de Tasca Síncrona
Utilitzant Operacions
Operacions i Cues d'Operacions
Les operacions proporcionen una manera més controlada de gestionar tasques concurrents. Pots crear subclasses de Operation
per definir tasques personalitzades.
Exemple de Cues d'Operacions
let operationQueue = OperationQueue() let operation1 = BlockOperation { print("Operació 1") } let operation2 = BlockOperation { print("Operació 2") } operationQueue.addOperation(operation1) operationQueue.addOperation(operation2)
Dependències entre Operacions
Pots establir dependències entre operacions per assegurar-te que es compleixin en un ordre específic.
Exemple de Dependències
let operation1 = BlockOperation { print("Operació 1") } let operation2 = BlockOperation { print("Operació 2") } operation2.addDependency(operation1) let operationQueue = OperationQueue() operationQueue.addOperations([operation1, operation2], waitUntilFinished: false)
Concurrència Segura
Condicions de Carrera
Les condicions de carrera ocorren quan múltiples fils accedeixen i modifiquen la mateixa dada al mateix temps. Això pot causar comportaments inesperats.
Utilitzant Barreres
Les barreres permeten assegurar que només una tasca accedeixi a una dada compartida a la vegada.
Exemple de Barrera
let concurrentQueue = DispatchQueue(label: "com.example.concurrentQueue", attributes: .concurrent) concurrentQueue.async(flags: .barrier) { // Codi que modifica dades compartides }
Utilitzant Semàfors
Els semàfors controlen l'accés a recursos compartits limitant el nombre de fils que poden accedir-hi al mateix temps.
Exemple de Semàfor
let semaphore = DispatchSemaphore(value: 1) DispatchQueue.global().async { semaphore.wait() // Codi que accedeix a dades compartides semaphore.signal() }
Exercicis Pràctics
Exercici 1: Utilitzant GCD
Crea una aplicació que descarregui una imatge des d'una URL en segon pla i la mostri en una UIImageView
a la interfície d'usuari.
Solució
import UIKit class ViewController: UIViewController { @IBOutlet weak var imageView: UIImageView! override func viewDidLoad() { super.viewDidLoad() downloadImage() } func downloadImage() { let url = URL(string: "https://example.com/image.jpg")! DispatchQueue.global().async { if let data = try? Data(contentsOf: url) { DispatchQueue.main.async { self.imageView.image = UIImage(data: data) } } } } }
Exercici 2: Utilitzant Operacions
Crea una aplicació que realitzi tres operacions en segon pla: descarregar dades, processar-les i actualitzar la interfície d'usuari. Assegura't que les operacions es compleixin en l'ordre correcte.
Solució
import UIKit class ViewController: UIViewController { @IBOutlet weak var label: UILabel! override func viewDidLoad() { super.viewDidLoad() performOperations() } func performOperations() { let operationQueue = OperationQueue() let downloadOperation = BlockOperation { // Simula la descàrrega de dades sleep(2) print("Dades descarregades") } let processOperation = BlockOperation { // Simula el processament de dades sleep(2) print("Dades processades") } let updateUIOperation = BlockOperation { // Actualitza la interfície d'usuari DispatchQueue.main.async { self.label.text = "Operacions completades" } } processOperation.addDependency(downloadOperation) updateUIOperation.addDependency(processOperation) operationQueue.addOperations([downloadOperation, processOperation, updateUIOperation], waitUntilFinished: false) } }
Resum
En aquest mòdul, has après els conceptes bàsics de la concurrència en Swift, incloent-hi l'ús de Grand Central Dispatch (GCD) i operacions per gestionar tasques concurrents. També has après a implementar concurrència segura per evitar condicions de carrera i altres problemes comuns. La concurrència és una eina poderosa que pot millorar significativament el rendiment i la resposta de les teves aplicacions, però cal utilitzar-la amb cura per evitar errors.
En el següent mòdul, explorarem el Gestor de Paquets Swift, una eina que et permetrà gestionar les dependències del teu projecte de manera eficient.
Curs de Programació en Swift
Mòdul 1: Introducció a Swift
- Introducció a Swift
- Configuració de l'Entorn de Desenvolupament
- El Teu Primer Programa en Swift
- Sintaxi i Estructura Bàsica
- Variables i Constants
- Tipus de Dades
Mòdul 2: Flux de Control
Mòdul 3: Funcions i Closures
- Definició i Crida de Funcions
- Paràmetres de Funció i Valors de Retorn
- Closures
- Funcions d'Ordre Superior
Mòdul 4: Programació Orientada a Objectes
Mòdul 5: Swift Avançat
Mòdul 6: Swift i Desenvolupament iOS
- Introducció al Desenvolupament iOS
- Conceptes Bàsics de UIKit
- Storyboards i Interface Builder
- Xarxes en Swift
- Core Data
- Conceptes Bàsics de SwiftUI