Несоответствующие данные области между потоками - PullRequest
0 голосов
/ 15 апреля 2020

У меня есть случай, когда мне нужно заполнить область серией объектов по запросу пользователя. Для заполнения области я делаю сетевой вызов, а затем записываю объекты в область. Когда запись завершена, фоновый поток вызывает обратный вызов, который переключается на основной поток для обработки результатов. Я бы предпочел использовать уведомления областей, но это очень конкретный c вариант использования, и уведомления не являются опцией.

Я не могу поделиться своим полным проектом, но мне удалось воспроизвести эту проблему с пример проекта. Вот моя модель данных.

class Owner: Object {
    @objc dynamic var uuid: String = ""
    @objc dynamic var name: String = ""

    convenience init(uuid: String, name: String) {
        self.init()
        self.uuid = uuid
        self.name = name
    }

    func fetchDogs() -> Results<Dog>? {
        return realm?.objects(Dog.self).filter("ownerID == %@", uuid)
    }

    override class func primaryKey() -> String? {
        return "uuid"
    }
}

class Dog: Object {
    @objc dynamic var uuid: String = ""
    @objc dynamic var name: String = ""
    @objc dynamic var ownerID: String = ""

    func fetchOwner() -> Owner? {
        return realm?.object(ofType: Owner.self, forPrimaryKey: ownerID)
    }

    convenience init(uuid: String, name: String, ownerID: String) {
        self.init()
        self.uuid = uuid
        self.name = name
        self.ownerID = ownerID
    }

    override class func primaryKey() -> String? {
        return "uuid"
    }
}

Я понимаю, что List будет подходящим для отношения Owner -> Dog, но это не вариант в этом проекте.

В примере проекта есть две кнопки, которые нас интересуют. Один для добавления некоторых Dog объектов в область и связывания их с Owner UUID. Другая кнопка удаляет все Dog объекты, принадлежащие владельцу.

Основной поток c выглядит следующим образом:

  • Удаление всех собак владельца
  • Создайте новый набор собак в фоновом потоке и добавьте их в область.
  • Вызовите обратный вызов
  • Переключитесь обратно в основной поток
  • Распечатайте все собаки владельца

Девять раз из десяти собак были успешно распечатаны. Однако иногда область указывает на то, что с текущим владельцем не связано ни одной собаки. Что может быть причиной этого? Мой логик контроллера вида c ниже.

РЕДАКТИРОВАТЬ: Последнее, что я должен упомянуть, это то, что эта проблема воспроизводится только на физическом устройстве. Я не могу воспроизвести это на симуляторе. Это заставляет меня задуматься, если это ошибка в области.

// MARK: - Props and view controller life cycle

class ViewController: UIViewController {

    var owner: Owner?
    let ownerUUID = UUID().uuidString

    override func viewDidLoad() {
        super.viewDidLoad()
        owner = makeOwner()
    }
}

// MARK: - Action methods

extension ViewController {

    @IBAction func onDeletePressed(_ sender: UIButton) {
        print("Deleting...")
        deleteDogs()
    }

    @IBAction func onRefreshPressed(_ sender: UIButton) {
        print("Creating...")
        createDogs {
            DispatchQueue.main.async {
                self.printDogs()
            }
        }
    }

    @IBAction func onPrintPressed(_ sender: UIButton) {
        printDogs()
    }
}

// MARK: - Helper methods

extension ViewController {

    private func makeOwner() -> Owner? {
        let realm = try! Realm()
        let owner = Owner(uuid: ownerUUID, name: "Bob")
        try! realm.write {
            realm.add(owner)
        }
        return owner
    }

    private func deleteDogs() {
        guard let dogs = owner?.fetchDogs() else { return }
        let realm = try! Realm()
        try! realm.write {
            realm.delete(dogs)
        }
    }

    private func createDogs(completion: @escaping () -> Void) {
        DispatchQueue(label: "create.dogs.background").async {
            autoreleasepool {
                let realm = try! Realm()
                let dogs = [
                    Dog(uuid: UUID().uuidString, name: "Fido", ownerID: self.ownerUUID),
                    Dog(uuid: UUID().uuidString, name: "Billy", ownerID: self.ownerUUID),
                    Dog(uuid: UUID().uuidString, name: "Sally", ownerID: self.ownerUUID),
                ]
                try! realm.write {
                    realm.add(dogs)
                }
            }
            completion()
        }
    }

    private func printDogs() {
        guard let dogs = owner?.fetchDogs() else { return }
        print("Dogs: \(dogs)")
    }
}

1 Ответ

1 голос
/ 16 апреля 2020

Похоже, собаки созданы в отдельном потоке; «фоновый поток», и поэтому у него не будет прогона l oop - поэтому два потока смотрят на разные состояния данных.

При создании объектов в потоке без runl oop, Realm.refre sh () необходимо вызвать вручную, чтобы перевести транзакцию в самое последнее состояние.

Ознакомьтесь с документацией по Просмотр изменений из других потоков

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...