Πώς συγχρονίζονται τα δεδομένα μεταξύ νημάτων (πλαισίου) στο iOS;
sobes.tech AI
Απάντηση από AI
Για συγχρονισμό, μπορούν να χρησιμοποιηθούν οι ακόλουθοι μηχανισμοί:
-
NSLock: Ένα απλό μπλοκαριστικό mutex.
let lock = NSLock() func doSomething() { lock.lock() // Κρίσιμη ενότητα κώδικα lock.unlock() } -
NSRecursiveLock: Επιτρέπει σε ένα νήμα να αποκτήσει ξανά το κλείδωμα χωρίς deadlock.
let recursiveLock = NSRecursiveLock() func recursiveFunction(level: Int) { recursiveLock.lock() if level < 3 { recursiveFunction(level: level + 1) } recursiveLock.unlock() } -
NSCondition: Επιτρέπει στα νήματα να περιμένουν μια συγκεκριμένη συνθήκη πριν συνεχίσουν.
let condition = NSCondition() var dataAvailable = false func producer() { condition.lock() // Παραγωγή δεδομένων dataAvailable = true condition.signal() // Σήμα στα αναμένοντα νήματα condition.unlock() } func consumer() { condition.lock() while !dataAvailable { condition.wait() // Περιμένει μέχρι να εκπληρωθεί η συνθήκη } // Επεξεργασία δεδομένων dataAvailable = false condition.unlock() } -
NSConditionLock: Ένα mutex που μπορεί να κρατηθεί μόνο αν μια συγκεκριμένη τιμή συνθήκης ισχύει.
let conditionLock = NSConditionLock(condition: 0) let DATA_READY = 1 func producer() { conditionLock.lock(when: 0) // Κλείδωμα όταν η συνθήκη είναι 0 // Παραγωγή δεδομένων conditionLock.unlock(withCondition: DATA_READY) // Ξεκλείδωμα και ρύθμιση της συνθήκης σε DATA_READY } func consumer() { conditionLock.lock(when: DATA_READY) // Κλείδωμα όταν η συνθήκη είναι DATA_READY // Επεξεργασία δεδομένων conditionLock.unlock(withCondition: 0) // Ξεκλείδωμα και ρύθμιση της συνθήκης σε 0 } -
Dispatch Queues (GCD): Χρήση διαδοχικών ουρών dispatch για πρόσβαση σε κοινόχρηστους πόρους.
let serialQueue = DispatchQueue(label: "com.yourapp.serialQueue") var sharedResource = 0 func updateResource() { serialQueue.async { // Πρόσβαση στο sharedResource μόνο από αυτήν την ουρά sharedResource += 1 } } -
NSOperationQueue: Επιτρέπει τον έλεγχο των εξαρτήσεων και των προτεραιοτήτων των λειτουργιών.
let operationQueue = OperationQueue() var sharedOperationResource = 0 let operation1 = BlockOperation { // Πρόσβαση στο sharedOperationResource sharedOperationResource += 1 } operationQueue.addOperation(operation1) -
Actors (Swift 5.5+): Παρέχουν απομόνωση κατάστασης, αποτρέποντας ταυτόχρονη πρόσβαση από διαφορετικά συμφραζόμενα.
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: Για συγχρονισμό των context δεδομένων, μπορούν να χρησιμοποιηθούν ιεραρχικά contexts (γονέας-απόγονος) ή mergeChanges(fromContextDidSaveNotification:).
// Παράδειγμα με ιεραρχία (γονέας - φόντο, παιδί - UI) let privateMoc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) privateMoc.persistentStoreCoordinator = persistentStoreCoordinator let mainMoc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) mainMoc.parent = privateMoc // Παράδειγμα με 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 { // Αν η αποθήκευση έγινε σε άλλο context mainMoc.perform { mainMoc.mergeChanges(fromContextDidSave: notification) } } } -
Ατομικές λειτουργίες: Χρήση ατομικών primitive (π.χ. από
os/lock.h) για απλές λειτουργίες.
Η επιλογή της μεθόδου εξαρτάται από την πολυπλοκότητα της εργασίας, τον τύπο των δεδομένων και τις απαιτήσεις απόδοσης. Οι Actors και GCD είναι σύγχρονες προσεγγίσεις που προτιμώνται.