Wie synchronisiert man Daten zwischen Threads (Kontext) in iOS?
sobes.tech KI
Antwort von AI
Für die Synchronisierung können die folgenden Mechanismen verwendet werden:
-
NSLock: Ein einfacher Mutex.
let lock = NSLock() func doSomething() { lock.lock() // Kritischer Abschnitt lock.unlock() } -
NSRecursiveLock: Ermöglicht es einem Thread, den Lock mehrfach zu erwerben, ohne Deadlock zu verursachen.
let recursiveLock = NSRecursiveLock() func recursiveFunction(level: Int) { recursiveLock.lock() if level < 3 { recursiveFunction(level: level + 1) } recursiveLock.unlock() } -
NSCondition: Ermöglicht Threads, auf eine bestimmte Bedingung zu warten, bevor sie fortfahren.
let condition = NSCondition() var dataAvailable = false func producer() { condition.lock() // Datenproduktion dataAvailable = true condition.signal() // Signalisieren an wartende Threads condition.unlock() } func consumer() { condition.lock() while !dataAvailable { condition.wait() // Warten, bis die Bedingung erfüllt ist } // Datenverarbeitung dataAvailable = false condition.unlock() } -
NSConditionLock: Ein Mutex, der nur erworben werden kann, wenn eine bestimmte Bedingung erfüllt ist.
let conditionLock = NSConditionLock(condition: 0) let DATA_READY = 1 func producer() { conditionLock.lock(when: 0) // Erwerben bei Bedingung 0 // Datenproduktion conditionLock.unlock(withCondition: DATA_READY) // Freigeben und Bedingung auf DATA_READY setzen } func consumer() { conditionLock.lock(when: DATA_READY) // Erwerben bei Bedingung DATA_READY // Datenverarbeitung conditionLock.unlock(withCondition: 0) // Freigeben und Bedingung auf 0 setzen } -
Dispatch Queues (GCD): Verwendung von sequentiellen Dispatch-Queues für den Zugriff auf gemeinsame Ressourcen.
let serialQueue = DispatchQueue(label: "com.yourapp.serialQueue") var sharedResource = 0 func updateResource() { serialQueue.async { // Zugriff auf sharedResource nur aus dieser Queue sharedResource += 1 } } -
NSOperationQueue: Ermöglicht die Kontrolle von Abhängigkeiten und Prioritäten von Operationen.
let operationQueue = OperationQueue() var sharedOperationResource = 0 let operation1 = BlockOperation { // Zugriff auf sharedOperationResource sharedOperationResource += 1 } operationQueue.addOperation(operation1) -
Actors (Swift 5.5+): Sichern die Isolierung des Zustands und verhindern gleichzeitigen Zugriff aus verschiedenen Kontexten.
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-Kontexte: Zur Synchronisierung von Data-Contexts können hierarchische Kontexte (Eltern-Kind) oder mergeChanges(fromContextDidSaveNotification:) verwendet werden.
// Beispiel mit Hierarchie (Eltern - Hintergrund, Kind - UI) let privateMoc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) privateMoc.persistentStoreCoordinator = persistentStoreCoordinator let mainMoc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) mainMoc.parent = privateMoc // Beispiel mit 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 { // Wenn das Speichern nicht im Hauptkontext erfolgte mainMoc.perform { mainMoc.mergeChanges(fromContextDidSave: notification) } } } -
Atomare Operationen: Verwendung von atomaren Primitive (z.B. aus
os/lock.h) für einfache Operationen.
Die Wahl der Methode hängt von der Komplexität der Aufgabe, dem Datentyp und den Leistungsanforderungen ab. Actors und GCD sind moderne, bevorzugte Ansätze.