मैंने CoreData स्टैक का नकली संस्करण बनाया है

import Foundation
import CoreData

@testable import Companion

final class MockedDatabaseStackController: DatabaseStackControllerProtocol {

    let batchRequestsAvailable: Bool = false

    private lazy var managedObjectModel = NSManagedObjectModel.mergedModel(from: [Bundle(for: type(of: self))])!

    lazy var persistentContainer: NSPersistentContainer = {
        let description = NSPersistentStoreDescription()
        description.type = NSInMemoryStoreType
        description.shouldAddStoreAsynchronously = false

        let container = NSPersistentContainer(
            name: "database",
            managedObjectModel: managedObjectModel
        )
        container.persistentStoreDescriptions = [description]
        container.loadPersistentStores { description, error in
            // Check if the data store is in memory
            precondition( description.type == NSInMemoryStoreType )

            // Check if creating container wrong
            if let error = error {
                fatalError("Create an in-mem coordinator failed \(error)")
            }
        }

        return container
    }()

    init() {
        NotificationCenter.default
            .addObserver(
                self,
                selector: #selector(didManagedObjectContextSave(notification:)),
                name: .NSManagedObjectContextDidSave,
                object: nil
            )
    }

    @objc
    private func didManagedObjectContextSave(notification: Notification) {
        DispatchQueue.main.async { [weak self] in
            self?.persistentContainer.viewContext.mergeChanges(fromContextDidSave: notification)
        }
    }
}

और मैं इसका उपयोग किसी वस्तु को बचाने के लिए कर रहा हूं:

private func executeAndSave<T>(_ executionBlock: @escaping ((NSManagedObjectContext) throws -> T)) -> Single<T> {
    let persistentContainer = stackController.persistentContainer

    return Single.create { observer in
        persistentContainer.performBackgroundTask { context in
            do {
                context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy

                jsons.forEach {
                    let mo = type.init(context: context)
                    mo.update(withGatewayResponse: $0)
                }
                try context.save()

                DispatchQueue.main.async {
                    observer(.success(result))
                }
            } catch {
                DispatchQueue.main.async {
                    observer(.error(error))
                }
            }
        }

        return Disposables.create()
    }
}

func save(jsons: [JSON], as type: GatewayObjectDeserializableAndSavable.Type) -> Single<Void> {
    if jsons.isEmpty {
        log.info("(\(type)) Nothing to save.")
        return .just(())
    }

    log.info("DatabaseHelper will save \(type)")

    return executeAndSave { context in
        jsons.forEach {
            let mo = type.init(context: context)
            mo.update(withGatewayResponse: $0)
        }
    }
}

// Example of usage:
databaseHelper.save(jsons: jsons, as: Herd.self)

मैंने डेटाबेस मॉडल में बाधाएं पैदा कीं, उदाहरण के लिए: यहां छवि विवरण दर्ज करें

लेकिन यह काम नहीं करता। डेटाबेस में ऑब्जेक्ट डुप्लिकेट। यहां छवि विवरण दर्ज करें

ध्यान दें कि मुख्य लक्ष्य में सब कुछ ठीक काम करता है जहां मैं इस CoreData के ढेर का उपयोग करता हूं:

final class DatabaseStackController: DatabaseStackControllerProtocol {

    // singleton
    static let controller = DatabaseStackController()

    private static let kDatabaseName = "database"
    let persistentContainer: NSPersistentContainer = DatabaseStackController.buildDatabaseStack(onComplete: nil)

    let batchRequestsAvailable: Bool = true

    private init() {
        addNSMangedObjectContextObservers()
    }

    private static func buildDatabaseStack(onComplete: (() -> Void)?) -> NSPersistentContainer {
        let container = NSPersistentContainer(name: kDatabaseName)
        container.loadPersistentStores { _, error in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }

            onComplete?()
        }

        return container
    }
}

यह काम क्यों नहीं करता? क्या NSInMemoryStoreType CoreData की बाधाओं का समर्थन नहीं करता है? क्या इसे ठीक करना संभव है?

6
Kamil Harasimowicz 10 मई 2019, 15:26

1 उत्तर

सबसे बढ़िया उत्तर

मुझे लगता है कि आपको कोर डेटा में एक बग मिला है :(

मेरे पास कोर डेटा की अद्वितीय बाधा के लिए एक छोटा डेमो प्रोजेक्ट है। मैंने पुष्टि की है कि यह अपेक्षानुसार काम करता है कुछ अपवादों को छोड़कर, हमेशा SQLite स्टोर के साथ सभी डुप्लीकेट मर्ज करना। फिर मैंने आपकी MockedDatabaseStackController कक्षा में चिपकाया और persistentContainer.viewContext को NSMergeByPropertyObjectTrumpMergePolicy सेट के साथ प्रयोग किया। परिणाम: ऐसा लगता है कि पहले सहेजें ऑपरेशन पर डुप्लिकेट के पहले सेट को मर्ज कर दिया गया है लेकिन उसके बाद कोई नहीं। फिर मैंने अपने कोर डेटा स्टैक पर वापस स्विच किया, सिवाय इसके कि मैंने स्टोर प्रकार को NSInMemoryStoreType में बदल दिया। परिणाम: यह आपके MockedDatabaseStackController के समान काम करने में भी विफल रहता है।

SQLite डेटाबेस जो कोर डेटा के SQLite स्टोर को रेखांकित करता है, अद्वितीय बाधा का समर्थन करता है इसके SQL में . मुझे आशा है कि कोई मुझे गलत साबित कर सकता है, लेकिन, दुख की बात है कि मुझे संदेह है कि Apple ने SQLite की इस सुविधा का उपयोग कोर डेटा में अद्वितीय बाधा सुविधा को लागू करने के लिए किया था, लेकिन उनके दस्तावेज़ तथ्य यह है कि यह केवल SQLite स्टोर के लिए काम करता है।

मैंने इसे Apple बग रिपोर्टर को सबमिट कर दिया है: 50725935।

आपके परीक्षण के अनुसार, मुझे लगता है कि आपको अस्थायी SQLite स्टोर बनाने के लिए इसे संशोधित करना चाहिए। वास्तव में कुछ विशेषताएं हैं जो वेन आरेख के दूसरी तरफ हैं - इन-मेमोरी स्टोर द्वारा समर्थित लेकिन SQLite स्टोर द्वारा समर्थित नहीं। इन-मेमोरी स्टोर के साथ परीक्षण करने से आपके परीक्षण कवरेज में छेद हो सकते हैं।

7
Jerry Krinock 13 मई 2019, 16:20