Hogyan szinkronizáljuk az adatokat a szálak (környezet) között az iOS-ben?
sobes.tech MI
Válasz az MI-től
A szinkronizációhoz az alábbi mechanizmusokat lehet használni:
-
NSLock: Egyszerű blokkoló mutex.
let lock = NSLock() func doSomething() { lock.lock() // Kritikus szekció kódja lock.unlock() } -
NSRecursiveLock: Lehetővé teszi egy szál számára, hogy többször is megszerezze a zárolást anélkül, hogy deadlock lépne fel.
let recursiveLock = NSRecursiveLock() func recursiveFunction(level: Int) { recursiveLock.lock() if level < 3 { recursiveFunction(level: level + 1) } recursiveLock.unlock() } -
NSCondition: Lehetővé teszi a szálaknak, hogy bizonyos feltételre várjanak, mielőtt folytatják.
let condition = NSCondition() var dataAvailable = false func producer() { condition.lock() // Adatgyártás dataAvailable = true condition.signal() // Jelzi a várakozó szálaknak condition.unlock() } func consumer() { condition.lock() while !dataAvailable { condition.wait() // Vár, amíg a feltétel teljesül } // Adatfeldolgozás dataAvailable = false condition.unlock() } -
NSConditionLock: Egy mutex, amely csak akkor fogható, ha egy adott feltétel-érték teljesül.
let conditionLock = NSConditionLock(condition: 0) let DATA_READY = 1 func producer() { conditionLock.lock(when: 0) // Zárolás, ha a feltétel 0 // Adatgyártás conditionLock.unlock(withCondition: DATA_READY) // Feloldás és a feltétel beállítása DATA_READY-ra } func consumer() { conditionLock.lock(when: DATA_READY) // Zárolás, ha a feltétel DATA_READY // Adatfeldolgozás conditionLock.unlock(withCondition: 0) // Feloldás és a feltétel beállítása 0-ra } -
Dispatch Queues (GCD): Szekvenciális dispatch-queue-k használata a közös erőforrásokhoz való hozzáféréshez.
let serialQueue = DispatchQueue(label: "com.yourapp.serialQueue") var sharedResource = 0 func updateResource() { serialQueue.async { // Hozzáférés a sharedResource-hoz csak ezen a queue-n keresztül sharedResource += 1 } } -
NSOperationQueue: Lehetővé teszi az operációk függőségeinek és prioritásainak kezelését.
let operationQueue = OperationQueue() var sharedOperationResource = 0 let operation1 = BlockOperation { // Hozzáférés a sharedOperationResource-hoz sharedOperationResource += 1 } operationQueue.addOperation(operation1) -
Actors (Swift 5.5+): Izolálják az állapotot, megakadályozva a párhuzamos hozzáférést különböző kontextusokból.
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: A data contextek szinkronizálására hierarchikus contexteket (szülő-gyermek) vagy mergeChanges(fromContextDidSaveNotification:) lehet használni.
// Hierarchikus példa (szülő - háttér, gyermek - UI) let privateMoc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) privateMoc.persistentStoreCoordinator = persistentStoreCoordinator let mainMoc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) mainMoc.parent = privateMoc // mergeChanges példa 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 { // Ha a mentés nem a fő kontextusban történt mainMoc.perform { mainMoc.mergeChanges(fromContextDidSave: notification) } } } -
Atomi műveletek: Egyszerű műveletekhez atomáris primitívek használata (pl.
os/lock.h-ből).
A módszer kiválasztása a feladat összetettségétől, az adatok típusától és a teljesítményigényektől függ. Az Actors és GCD modern és előnyben részesített megközelítések.