¿Cómo sincronizar datos entre hilos y garantizar la coherencia del contexto?
sobes.tech AI
Respuesta de la IA
Para la sincronización de datos y garantizar la coherencia del contexto en una aplicación multihilo en iOS, se utilizan los siguientes enfoques:
-
NSLock / Lock: Mutex simples para bloquear secciones críticas del código.
import Foundation class ThreadSafeCounter { private var count: Int = 0 private let lock = NSLock() func increment() { lock.lock() defer { lock.unlock() } // Liberación garantizada del bloqueo count += 1 } func getCount() -> Int { lock.lock() defer { lock.unlock() } return count } } -
NSRecursiveLock: Permite volver a adquirir el bloqueo desde el mismo hilo.
import Foundation class RecursiveLocker { private let lock = NSRecursiveLock() func firstMethod() { lock.lock() defer { lock.unlock() } print("Primer método") secondMethod() // La adquisición repetida es posible } func secondMethod() { lock.lock() defer { lock.unlock() } print("Segundo método") } } -
NSCondition / NSConditionLock: Permiten que los hilos esperen una condición específica o un valor antes de continuar. Se utilizan para implementar el patrón productor-consumidor.
import Foundation class Buffer { private var items: [Int] = [] private let condition = NSCondition() private let capacity = 5 func addItem(_ item: Int) { condition.lock() defer { condition.unlock() } while items.count == capacity { condition.wait() // Espera hasta que haya espacio libre } items.append(item) print("Añadido: \(item), Buffer actual: \(items)") condition.signal() // Señala a los hilos que esperan } func removeItem() -> Int { condition.lock() defer { condition.unlock() } while items.isEmpty { condition.wait() // Espera hasta que haya un elemento } let item = items.removeFirst() print("Eliminado: \(item), Buffer actual: \(items)") condition.signal() // Señala a los hilos que esperan espacio return item } } -
Grand Central Dispatch (GCD):
-
Colas seriales: Ejecutan tareas de forma secuencial, una a la vez en la misma hebra, garantizando la atomicidad del acceso a los recursos.
-
Colas concurrentes con banderas Barrier: Permiten realizar lecturas concurrentemente, pero las operaciones de escritura (write) se realizan de forma exclusiva. Esto implementa un modelo de bloqueo lectura-escritura.
import Foundation class ThreadSafeArray<Element> { private var array: [Element] = [] private let queue = DispatchQueue(label: "com.mycompany.threadsafearray", attributes: .concurrent) // Cola concurrente func append(_ newElement: Element) { queue.async(flags: .barrier) { // Barrera para escritura self.array.append(newElement) } } func get(at index: Int) -> Element? { var result: Element? queue.sync { // Sincronización para lectura (o async, si el orden no importa) if index < self.array.count { result = self.array[index] } } return result } }
-
-
Operaciones de Contexto de Core Data: Cada
NSManagedObjectContexttiene su propio hilo serial privado. El acceso a objetos y al contexto debe realizarse solo desde ese hilo.import CoreData // Ejemplo de guardado en el contexto de Core Data let context = // Contexto obtenido context.perform { // Ejecución en el hilo privado del contexto // Trabajar con objetos de Core Data aquí do { try context.save() } catch { // Manejo del error } }
La elección del método depende de la tarea específica y los requisitos de rendimiento. GCD con colas seriales o colas concurrentes con barreras suele ser la opción más preferida por su eficiencia y facilidad de uso. Para Core Data, siempre utilice los métodos perform o performAndWait.