web-dev-qa-db-ja.com

Swift 5でコアデータの永続性を構成する

私は 次のチュートリアル を使用して、コアデータをSwift IOSアプリケーションに実装します。ビデオに示すように、永続マネージャーシングルトンパターンを介して作成されます。これを記述するコードは次のとおりです。

import Foundation
import CoreData

class DataLogger {

    private init() {}
    static let shared = DataLogger()
    lazy var context = persistentContainer.viewContext

    private var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "mycoolcontainer")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                print("Unresolved error \(error), \(error.userInfo)")
            }
        })
        return container
    }()

    func save () {
        if self.context.hasChanges {
            self.context.perform {
                do {
                    try self.context.save()
                } catch {
                    print("Failure to save context: \(error)")
                }
            }
        }
    }
}

ここで、次のコードを使用してエンティティの要素(MyEntityはCore Dataエンティティオブジェクト)を約1000個ほど含むループを作成すると、アプリケーションがクラッシュします。

class MySampleClass {

    static func doSomething {
        for i in 0 ..< 1000 {
            let entry = MyEntity(context: DataLogger.shared.context);
            // do random things
        }
        DataLogger.shared.save()
    }
}

MyEntity(context:DataLogger.shared.context)でクラッシュし、ログを観察して理由を確認できません。ときどき、save()コールに到達し、成功するか、次の一般的なエラーでクラッシュします。

ヒープの破損が検出され、空きリストが0x280a28240で破損しています***不正なガード値:13859718129998653044

私はネットを調べて、問題が何であるかについてのヒントを見つけようとしました。 .performAndWait()を介して、DataLoggerのsave()メソッドを同期させようとしましたが、成功しませんでした。また、次のコードを使用して、childContextsを使用して同じことを実行しようとしましたが、成功しませんでした。

let childContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
childContext.parent = context
childContext.hasChanged {
    childContext.save();
}

私はDataLoggerクラスを正しく実装していないと思いますが、実際の問題が何であるかを観察することはできません。作成されたオブジェクトの数、またはスレッド化に関連している可能性がありますが、確信はありません。 DataLoggerクラスを実装して他のクラスがそれを使用してエンティティをディスクに保存できるようにする正しい方法は何でしょうか?

7
angryip

これを試して...

class MySampleClass {

    let dataLogger = DataLogger.shared
    let context = dataLogger.context

    static func doSomething {
        for i in 0 ..< 1000 {
            let entry = MyEntity(context: context);
            // do random things
        }
        dataLogger.save()
    }
}

クラスでDataLoggerシングルトン参照をインスタンス化し、プロパティをそのコンテキストに設定することにより、DataLoggerクラスへの繰り返しの呼び出しを保存する必要があるローカル参照を保持しています。

以下は「副次的な問題」のコメントです-それはあなたの問題の一部であるとは思いません-しかし...電話をかける必要があるかわかりませんself.context.perform {}。他の人はおそらくその理由を説明するのに十分な情報を得ています。個人的に私はいくつかの調査を行い、理由がわかれば答えを更新します。

0
andrewbuilder