Cum să sincronizezi datele între fire (context) în iOS?
sobes.tech AI
Răspuns de la AI
Pentru sincronizare, se pot folosi următoarele mecanisme:
-
NSLock: Un mutex simplu de blocare.
let lock = NSLock() func doSomething() { lock.lock() // Secțiunea critică a codului lock.unlock() } -
NSRecursiveLock: Permite unui thread să obțină de mai multe ori blocarea fără deadlock.
let recursiveLock = NSRecursiveLock() func recursiveFunction(level: Int) { recursiveLock.lock() if level < 3 { recursiveFunction(level: level + 1) } recursiveLock.unlock() } -
NSCondition: Permite thread-urilor să aștepte pentru o anumită condiție înainte de a continua.
let condition = NSCondition() var dataAvailable = false func producer() { condition.lock() // Producție de date dataAvailable = true condition.signal() // Semnalează thread-urile în așteptare condition.unlock() } func consumer() { condition.lock() while !dataAvailable { condition.wait() // Așteaptă până când condiția este îndeplinită } // Procesare date dataAvailable = false condition.unlock() } -
NSConditionLock: Un mutex care poate fi deținut doar dacă o anumită condiție-valoare este îndeplinită.
let conditionLock = NSConditionLock(condition: 0) let DATA_READY = 1 func producer() { conditionLock.lock(when: 0) // Obține blocarea când condiția este 0 // Producție de date conditionLock.unlock(withCondition: DATA_READY) // Eliberează blocarea și setează condiția la DATA_READY } func consumer() { conditionLock.lock(when: DATA_READY) // Obține blocarea când condiția este DATA_READY // Procesare date conditionLock.unlock(withCondition: 0) // Eliberează blocarea și setează condiția la 0 } -
Dispatch Queues (GCD): Utilizarea cozii de dispatch secvențiale pentru accesul la resursele comune.
let serialQueue = DispatchQueue(label: "com.yourapp.serialQueue") var sharedResource = 0 func updateResource() { serialQueue.async { // Acces la sharedResource doar din această coadă sharedResource += 1 } } -
NSOperationQueue: Permite controlul dependențelor și priorităților operațiilor.
let operationQueue = OperationQueue() var sharedOperationResource = 0 let operation1 = BlockOperation { // Acces la sharedOperationResource sharedOperationResource += 1 } operationQueue.addOperation(operation1) -
Actors (Swift 5.5+): Asigură izolarea stării, prevenind accesul concurent din diferite contexte.
actor Counter { private var count = 0 func increment() { count += 1 } func getCount() -> Int { return count } } let counter = Counter() Task { await counter.increment() let currentCount = await counter.getCount() print(currentCount) } -
Core Data Contexts: Pentru sincronizarea contextelor de date, se pot folosi contexte ierarhice (părinte - copil) sau mergeChanges(fromContextDidSaveNotification:).
// Exemplu cu ierarhie (părinte - background, copil - UI) let privateMoc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) privateMoc.persistentStoreCoordinator = persistentStoreCoordinator let mainMoc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) mainMoc.parent = privateMoc // Exemplu cu mergeChanges NotificationCenter.default.addObserver(self, selector: #selector(contextDidSave(_:)), name: .NSManagedObjectContextDidSave, object: nil) @objc func contextDidSave(_ notification: Notification) { guard let savingContext = notification.object as? NSManagedObjectContext else { return } if savingContext != mainMoc { // Dacă salvarea s-a făcut în alt context decât cel principal mainMoc.perform { mainMoc.mergeChanges(fromContextDidSave: notification) } } } -
Operații atomice: Utilizarea primitivelelor atomice (de exemplu, din
os/lock.h) pentru operații simple.
Alegerea metodei depinde de complexitatea sarcinii, tipul de date și performanța necesară. Actorii și GCD sunt abordări moderne preferate.