Hoe synchroniseer je gegevens tussen threads (context) in iOS?
sobes.tech AI
Antwoord van AI
Voor synchronisatie kunnen de volgende mechanismen worden gebruikt:
-
NSLock: Eenvoudige blokkerende mutex.
let lock = NSLock() func doSomething() { lock.lock() // Kritische sectie code lock.unlock() } -
NSRecursiveLock: Maakt het mogelijk voor één thread om meerdere keren een lock te verkrijgen zonder deadlock.
let recursiveLock = NSRecursiveLock() func recursiveFunction(level: Int) { recursiveLock.lock() if level < 3 { recursiveFunction(level: level + 1) } recursiveLock.unlock() } -
NSCondition: Laat threads wachten op een bepaalde voorwaarde voordat ze verder gaan.
let condition = NSCondition() var dataAvailable = false func producer() { condition.lock() // Data productie dataAvailable = true condition.signal() // Signaleer wachtende threads condition.unlock() } func consumer() { condition.lock() while !dataAvailable { condition.wait() // Wacht tot de voorwaarde voldaan is } // Data verwerking dataAvailable = false condition.unlock() } -
NSConditionLock: Een mutex die alleen kan worden vastgehouden als aan een bepaalde voorwaarde-waarde wordt voldaan.
let conditionLock = NSConditionLock(condition: 0) let DATA_READY = 1 func producer() { conditionLock.lock(when: 0) // Vergrendel bij voorwaarde 0 // Data productie conditionLock.unlock(withCondition: DATA_READY) // Ontgrendel en stel voorwaarde in op DATA_READY } func consumer() { conditionLock.lock(when: DATA_READY) // Vergrendel bij voorwaarde DATA_READY // Data verwerking conditionLock.unlock(withCondition: 0) // Ontgrendel en stel voorwaarde in op 0 } -
Dispatch Queues (GCD): Gebruik van sequentiële dispatch-queues voor toegang tot gedeelde bronnen.
let serialQueue = DispatchQueue(label: "com.yourapp.serialQueue") var sharedResource = 0 func updateResource() { serialQueue.async { // Toegang tot sharedResource alleen via deze queue sharedResource += 1 } } -
NSOperationQueue: Maakt het mogelijk om afhankelijkheden en prioriteiten van operaties te beheren.
let operationQueue = OperationQueue() var sharedOperationResource = 0 let operation1 = BlockOperation { // Toegang tot sharedOperationResource sharedOperationResource += 1 } operationQueue.addOperation(operation1) -
Actors (Swift 5.5+): Bieden isolatie van toestand, voorkomen gelijktijdige toegang vanuit verschillende contexten.
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: Voor het synchroniseren van data-omgevingen kunnen hiërarchische contexts (ouder-kind) of mergeChanges(fromContextDidSaveNotification:) worden gebruikt.
// Voorbeeld met hiërarchie (ouder - achtergrond, kind - UI) let privateMoc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) privateMoc.persistentStoreCoordinator = persistentStoreCoordinator let mainMoc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) mainMoc.parent = privateMoc // Voorbeeld met 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 { // Als de save niet in de hoofdcontext plaatsvond mainMoc.perform { mainMoc.mergeChanges(fromContextDidSave: notification) } } } -
Atomic operations: Gebruik van atomare primitieve operaties (bijvoorbeeld uit
os/lock.h) voor eenvoudige operaties.
De keuze van methode hangt af van de complexiteit van de taak, het type gegevens en de vereiste prestaties. Actors en GCD zijn moderne benaderingen die de voorkeur genieten.