NSInMemoryStoreType与NSBatchDeleteRequest不兼容吗?

时间:2017-07-17 00:11:54

标签: core-data nspersistentstore nsbatchdeleterequest

我目前正在对与Core Data交互的图层进行单元测试。它保存,删除和更新Item对象。但是,我尝试保存几个Item然后执行批量删除的测试仍然失败。

这是Item

extension Item {

    // MARK: - Properties

    @NSManaged public var date: NSDate

    @NSManaged public var isTaxable: Bool

    @NSManaged public var name: String

    @NSManaged public var price: NSDecimalNumber

    @NSManaged public var quantity: Double

    // MARK: - Fetch Requests

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Item> { return NSFetchRequest<Item>(entityName: "Item") }

    // MARK: - Validation

    // Manual validation for `Decimal` values is needed. A radar is still open, which is located at https://openradar.appspot.com/13677527.
    public override func validateValue(_ value: AutoreleasingUnsafeMutablePointer<AnyObject?>, forKey key: String) throws {
        if key == "price", let decimal = value.pointee as? Decimal { if decimal < Decimal(0.01) { throw NSError(domain: NSCocoaErrorDomain, code: 1620, userInfo: ["Item": self]) } }
        if key == "quantity", let double = value.pointee as? Double { if double == 0 { throw NSError(domain: NSCocoaErrorDomain, code: 1620, userInfo: ["Item": self]) } }
    }

}

这是与核心数据CoreDataStack交互的对象:

internal class CoreDataStack {

    // MARK: - Properties

    private let modelName: String

    internal lazy var storeContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: self.modelName)
        container.loadPersistentStores { (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } }
        return container
    }()

    internal lazy var managedContext: NSManagedObjectContext = { return self.storeContainer.viewContext }()

    // MARK: - Initialization

    internal init(modelName: String = "Cart") { self.modelName = modelName }

    // MARK: - Saving

    internal func saveContext() throws {
        guard managedContext.hasChanges else { return }
        do { try managedContext.save() } catch let error as NSError { throw error }
    }

}

这是使用Core Data管理持久性的对象:

internal final class ItemPersistenceService {

    // MARK: - Properties

    private let coreDataStack: CoreDataStack

    // MARK: - Initialization

    internal init(coreDataStack: CoreDataStack) {
        self.coreDataStack = coreDataStack
        print("init(coreDataStack:) - ItemPersistenceService")
    }

    // MARK: - Saving

    @discardableResult internal func saveItem(withInformation information: ItemInformation) throws -> Item {
        let item = Item(context: coreDataStack.managedContext)
        item.name = information.name
        item.quantity = information.quantity
        item.price = information.price as NSDecimalNumber
        item.date = information.date as NSDate
        item.isTaxable = information.isTaxable
        do {
            try coreDataStack.saveContext()
        } catch let error as NSError {
            throw error
        }
        return item
    }

    // MARK: - Deleting

    internal func delete(item: Item) throws {
        coreDataStack.managedContext.delete(item)
        do {
            try coreDataStack.saveContext()
        } catch let error as NSError {
            throw error
        }
    }

    internal func deleteAllItems() throws {
        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: Item.description())
        let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
        do {
            try coreDataStack.managedContext.persistentStoreCoordinator?.execute(deleteRequest, with: coreDataStack.managedContext)
        } catch let error as NSError {
            throw error
        }
    }

     // MARK: - Fetching

    internal func itemsCount() throws -> Int {
        let fetchRequest = NSFetchRequest<NSNumber>(entityName: Item.description())
        fetchRequest.resultType = .countResultType
        do {
            let result = try coreDataStack.managedContext.fetch(fetchRequest)
            guard let count = result.first?.intValue else { fatalError("Invalid result") }
            return count
        } catch {
            throw error
        }
    }

}

这是我用于测试的CoreDataStack子类,它包含一个内存存储:

internal final class TestCoreDataStack: CoreDataStack {

    // MARK: - Initialization

    internal override init(modelName: String = "Cart") {
        super.init(modelName: modelName)
        let persistentStoreDescription = NSPersistentStoreDescription()
        persistentStoreDescription.type = NSInMemoryStoreType
        let container = NSPersistentContainer(name: modelName)
        container.persistentStoreDescriptions = [persistentStoreDescription]
        container.loadPersistentStores { (storeDescription, error) in
            if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") }
            self.storeContainer = container
        }
    }

}

最后,这是一个持续失败的测试:

internal func test_ItemPersistenceService_Delete_All_Managed_Object_Context_Saved() {
    do {
        try service.saveItem(withInformation: information)
        try service.saveItem(withInformation: information)
    } catch { XCTFail("Expected `Item`") }
    expectation(forNotification: .NSManagedObjectContextDidSave, object: coreDataStack.managedContext) { (notification) in return true }
    do { try service.deleteAllItems() } catch { XCTFail("Expected deletion") }
    waitForExpectations(timeout: 2.0) { error in XCTAssertNil(error, "Expected save to occur") }
}

问题

NSInMemoryStoreType与NSBatchDeleteRequest不兼容吗?

如果没有,那么我做错了什么导致我的测试反复失败?

2 个答案:

答案 0 :(得分:1)

您始终可以创建SQLite类型的持久性存储并将其存储在/dev/null处。这是在快速XCTest类上执行此操作的代码:

var container: NSPersistentContainer!

override func setUp() {
    super.setUp()
    container = NSPersistentContainer(name: "ModelName")
    container.persistentStoreDescriptions[0].url = URL(fileURLWithPath: "/dev/null")
    container.loadPersistentStores { (description, error) in
        XCTAssertNil(error)
    }
}

答案 1 :(得分:0)

我希望使用相同的方法有效地删除大量对象,但是此页面指出NSBatchDeleteRequest仅与SQLite持久存储类型兼容,不支持内存存储类型。

https://developer.apple.com/library/content/featuredarticles/CoreData_Batch_Guide/BatchDeletes/BatchDeletes.html

  

重要提示:批量删除仅在您使用时才可用   SQLite持久性存储

此处列出了不同的持久性商店类型:

https://developer.apple.com/documentation/coredata/nspersistentstorecoordinator/persistent_store_types