Sobes.tech
Middle+

Чӣ гуна ҳамоҳангсозии маълумот байни ҷараёнҳо ва таъмин намудани мувофиқати контекст?

sobes.tech AI

Ҷавоб аз AI

Для синхронізації даних і забезпечення узгодженості контексту в багатопоточному додатку на iOS використовуються наступні підходи:

  1. NSLock / Lock: Простий мьютекс для блокування критичних секцій коду.

    import Foundation
    
    class ThreadSafeCounter {
        private var count: Int = 0
        private let lock = NSLock()
    
        func increment() {
            lock.lock()
            defer { lock.unlock() } // Гарантоване зняття блокування
            count += 1
        }
    
        func getCount() -> Int {
            lock.lock()
            defer { lock.unlock() }
            return count
        }
    }
    
  2. NSRecursiveLock: Дозволяє повторно захоплювати блокування з того ж потоку.

    import Foundation
    
    class RecursiveLocker {
        private let lock = NSRecursiveLock()
    
        func firstMethod() {
            lock.lock()
            defer { lock.unlock() }
            print("Перша метод")
            secondMethod() // Повторне захоплення можливо
        }
    
        func secondMethod() {
            lock.lock()
            defer { lock.unlock() }
            print("Друга метод")
        }
    }
    
  3. NSCondition / NSConditionLock: Дозволяє потокам чекати на певну умову (Condition) або значення (ConditionLock) перед продовженням виконання. Використовується для реалізації патерну producer-consumer.

    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() // Чекаємо, поки з'явиться вільне місце
            }
    
            items.append(item)
            print("Додано: \(item), Поточний буфер: \(items)")
            condition.signal() // Сигналізує потоки, які чекають
        }
    
        func removeItem() -> Int {
            condition.lock()
            defer { condition.unlock() }
    
            while items.isEmpty {
                condition.wait() // Чекаємо, поки з'явиться елемент
            }
    
            let item = items.removeFirst()
            print("Видалено: \(item), Поточний буфер: \(items)")
            condition.signal() // Сигналізує потокам, які чекають місце
            return item
        }
    }
    
  4. **Grand Central Dispatch (GCD):

    • Serial Queues: Виконують задачі послідовно, по одній за раз на даному потоці, що забезпечує атомарність доступу до ресурсів.

    • Concurrent Queues з Barrier Flags: Дозволяють виконувати читання одночасно, але операції запису (write) виконуються ексклюзивно. Це реалізує модель read-write lock.

      import Foundation
      
      class ThreadSafeArray<Element> {
          private var array: [Element] = []
          private let queue =
          DispatchQueue(label: "com.mycompany.threadsafearray", attributes: .concurrent) // Конкурентна черга
      
          func append(_ newElement: Element) {
              queue.async(flags: .barrier) { // Barrier для запису
                  self.array.append(newElement)
              }
          }
      
          func get(at index: Int) -> Element? {
              var result: Element?
              queue.sync { // Синхронізація для читання (або async, якщо порядок читання не важливий)
                  if index < self.array.count {
                      result = self.array[index]
                  }
              }
              return result
          }
      }
      
  5. Операції Core Data Context: Кожен NSManagedObjectContext має власний приватний серіалізований потік. Доступ до об'єктів і контексту слід виконувати лише з цього потоку.

    import CoreData
    
    // Приклад збереження у контексті Core Data
    let context = // Отриманий контекст
    context.perform { // Виконання на приватному потоці контексту
        // Робота з об'єктами Core Data
        do {
            try context.save()
        } catch {
            // Обробка помилки
        }
    }
    

Вибір методу залежить від конкретного завдання та вимог до продуктивності. GCD з серійними чергами або конкурентними чергами з бар'єрами часто є найкращим підходом через свою ефективність та зручність використання. Для Core Data обов'язково використовуйте методи perform або performAndWait.