创建到CoreData的通用MVVM连接器的问题



首先,很抱歉这篇文章的长度,但我是iOS和SwiftUI开发的新手,我不想错过任何细节。我在Android和Flutter上用Kotlin做过一些小项目,所以我有一些应用开发的经验。

<<h3>上下文/h3>我试图创建一个简单的应用程序,在CoreData上持久化用户数据,我试图遵循MVVM架构来开发应用程序。我受到以下媒体帖子的启发。我有以下文件:

  • DataSource.swift:抽象NSPersistentContainer初始化的类。
  • entity .swift: CoreData实体类标准化协议。
  • productenty .swift:符合实体协议的特定CoreData类定义。
  • model .swift:带有实体泛型的类,抽象了模型的实例化和更新过程。
  • ProductModel.swift:继承Model的特定CoreData实体模型定义(异常引发))。

例外我得到了一个异常初始化ProductsModel类(ProductsModel.swift,检查下面),我不知道错误来源和原因在哪里。

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'An instance of NSFetchedResultsController requires a fetch request with sort descriptors'

我希望你能给我一些线索!:)

的代码DataSource.swift:

import Foundation
import CoreData
let defaultDatabase = "DB"
class DataSource {
static let shared = DataSource()
public let container: NSPersistentContainer

init(dbName: String = defaultDatabase) {
container = NSPersistentContainer(name: dbName)
container.loadPersistentStores { (_, err) in
if let error = err as NSError? {
print("NSError (error) - (error.userInfo)")
return
}
}
}

func save() {
do {
print("Saving context")
try self.container.viewContext.save()
print("Successfully saved context")
} catch {
print("ERROR: (error as NSObject)")
}
}
}

Entity.swift:

import CoreData
protocol Entity: NSFetchRequestResult {
associatedtype CurrentEntity: NSManagedObject
static var name: String { get }
}

ProductEntity.swift:

import os
import CoreData
@objc(ProductEntity)
public class ProductEntity: NSManagedObject, Entity {
typealias CurrentEntity = ProductEntity
static let name: String = "Product"
}
extension ProductEntity : Identifiable {
public var ID: String {
self.objectID.uriRepresentation().absoluteString
}
}
extension ProductEntity {
@NSManaged public var desc: String?
@NSManaged public var name: String
@NSManaged public var price: Double
@NSManaged public var rations: Int16
@NSManaged public var shoppingList: NSSet?
}

Model.swift:

import Combine
import CoreData
import os
class Model<T: Entity>: NSObject, ObservableObject, NSFetchedResultsControllerDelegate {
var records = CurrentValueSubject<[T.CurrentEntity], Never>([])
private let controller: NSFetchedResultsController<T.CurrentEntity>

override init() {
controller = NSFetchedResultsController(
fetchRequest: NSFetchRequest<T.CurrentEntity>(entityName: T.name),
managedObjectContext: DataSource.shared.container.viewContext,
sectionNameKeyPath: nil, cacheName: nil
)

super.init()

controller.delegate = self

do {
try controller.performFetch()
records.value = (controller.fetchedObjects ?? []) as [T.CurrentEntity]
} catch {
NSLog("Error: could not fetch objects")
}
}

public func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
guard let records = controller.fetchedObjects as? [T.CurrentEntity] else { return }
self.records.value = records
}

public func save() {
DataSource.shared.save()
}
}

ProductModel.swift:

import os
class ProductsModel: Model<ProductEntity> {
static let shared: ProductsModel = ProductsModel() // <-- This line raise the exception
}

NSFetchedResultsController是一个工具,可以管理您的搜索结果从核心数据。它至少需要一个排序描述符来维护获取请求的列表。因此,您应该像下面那样改进您定义的NSFetchRequest来解决异常。

let req = NSFetchRequest<T.CurrentEntity>(entityName: T.name)
req.sortDescriptors = [NSSortDescriptor(key: "someKeyForSort", ascending: true)]

另外,"someKeyForSort"T.CurrentEntity的一个属性名。如果ProductEntity是类型,则"name";可能是关键字,假设您希望NSFetchedResultsController维护按名称升序排序的获取结果。

最新更新