Базовые данные иногда теряют данные - PullRequest
0 голосов
/ 09 февраля 2019

Мы запускаем приложение через Citrix Secure Hub, иногда возникает откат с потерей некоторых данных в CoreData.

Как я понимаю, CoreData имеет что-то вроде рабочей копии всех объектов, а иногда пытается сохранить это в файловой системе.

Хорошо пытались смоделировать поведение, но безуспешно, мы не могли обнаружить потерю данных или откат данных в нашей тестовой среде.

Так есть ли способ заставить iOS записать текущую «рабочую копию» на диск, чтобы предотвратить потерю данных при использовании слишком большого количества памяти (и, возможно, сбой)?Мы вызываем нашу функцию сохранения после

Как мы уже узнали:

Мы НЕ использовали:

func applicationWillResignActive(_ application: UIApplication) {
      print("applicationWillResignActive")
}

для сохранения контекста, может ли это быть проблемой (мыуже сохраняют контекст после каждого создаваемого объекта?И хорошо ли, возможно, вылетать в приложение, чтобы предотвратить борьбу пользователя с потерей данных?

Редактировать: это используемый Core Data Handler:

import Foundation
import CoreData

let context = CoreDataManager.shared.managedObjectContext

func saveContext(_ completion: (() -> Void)? = nil) {

     CoreDataManager.shared.save(completion)
}

func saveContextSync() {

     CoreDataManager.shared.saveSync()
}

class CoreDataManager: NSObject {

    static let shared = CoreDataManager()

    lazy var managedObjectContext: NSManagedObjectContext = {

    var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)

    managedObjectContext.persistentStoreCoordinator = persistentStoreCoordinator

    return managedObjectContext
}()

И наша функция сохранения:

@objc func save(_ completion: (() -> Void)?) {

    saveAsync(completion)
}

func saveAsync(_ completion: (() -> Void)?) {

    func save() {

        context.perform {
            do { try context.save() }
            catch {
              // HERE WE NEED TO HANDLE IT FOR A PRODUCTIVE ENVIRONMENT
            }

            completion?()
        }
    }

    if Thread.isMainThread {
        save()
    } else {
        DispatchQueue.main.async {
            save()
        }
    }

}

func saveSync() {

    func save() {
        context.performAndWait {
            do { try context.save() }
            catch { print(error)
                // TRY TO REPRODUCE MEMORY LOSS APP TO SEE WHAT HAPPENS
                abort()
            }
        }
    }

    if Thread.isMainThread {
        save()
    } else {
        DispatchQueue.main.sync {
            save()
        }
    }
}

Редактировать 2: Этот вопрос в Задаче C должен быть очень похож:

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

Редактировать 3: Кажется, что нет сбоя, некоторые пользователи говорят мне, что они добавляют данные, затем просто нажмите кнопку «Домой», и через пару часов данные из последней «задачи» будут потеряны.

1 Ответ

0 голосов
/ 24 февраля 2019

Есть три возможных причины.

Конфликты записи

Основные данные, как правило, требуют, чтобы запись выполнялась одним синхронным способом.Если вы одновременно пишете в один и тот же объект несколькими способами (даже если они касаются разных свойств и не конфликтуют строго), это будет конфликт слияния.Вы можете установить политику слияния (по умолчанию значение равно «error» - это означает, что изменения не применяются), но это действительно плохое решение, потому что вы приказываете core-data потерять информацию в молчании.см. Параллелизм NSPersistentContainer для сохранения в основные данные для настройки для предотвращения конфликтов слияния.

Закрытие приложения с несохраненными данными

Если вы правильно настроили свои основные данные, это не должноне бываетПравильный способ настройки основных данных - читать только из «viewContext» и записывать синхронно.Каждая запись выполняется в одном атомарном блоке, а пользовательский интерфейс обновляется только после его сохранения.Если вы отображаете информацию из контекста, который не сохранен на диск, это может быть проблемой.Например, кажется, что ваше приложение использует только один контекст основного потока как для чтения, так и для записи.Внесение изменений в этот контекст и отсутствие вызова сохранения оставит приложение в состоянии, когда есть важные изменения, которые имеются только в памяти, а не на диске.

Произошла ошибка при сохранении на диск

Это, безусловно, самое редкое событие, но есть пользователи, у которых действительно полно дисков.Если это произойдет, НИЧЕГО, что вы можете сделать, чтобы сохранить.На диске нет места физически.Как правило, правильно сказать пользователю и оставить все как есть.


Не зная больше о вашей конкретной настройке, трудно сказать наверняка, в чем ваша проблема.Я бы порекомендовал следующую настройку:

  1. использовать NSPersistentContainer
  2. только читать из viewContext и никогда не записывать в него.
  3. сделать очередь операций длязапись в базовые данные
  4. для каждой операции, создание контекста, внесение в него изменений, а затем сохранение.Не передавайте управляемые объекты в эти блоки или из них.

Это должно касаться всех проблем, кроме третьей.

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