【发布时间】:2021-11-15 19:57:29
【问题描述】:
首先,很抱歉帖子的长度,但我对 iOS 和 SwiftUI 开发非常陌生,我不想错过任何细节。我在 Android 和 Flutter 上使用 Kotlin 做过一些小项目,所以我有一些应用开发经验。
上下文
我尝试创建一个简单的应用程序,将用户数据保存在 CoreData 上,并且我尝试遵循 MVVM 架构来开发应用程序。我受到了 Medium 上的 post 的启发。我有以下文件:
-
DataSource.swift:抽象
NSPersistentContainer的初始化的类。 - Entity.swift:CoreData 实体类标准化协议。
- ProductEntity.swift:符合 Entity 协议的特定 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必须至少有一个排序描述符。 developer.apple.com/documentation/coredata/…。您可以将排序键传递给模型初始化程序。老实说,如果您刚刚开始尝试采用 MVVM,那么您可能会让自己的生活变得艰难,除非您在另一个平台上对此有丰富的经验。 MVVM 并不适合 iOS,尤其是在您使用 UIKit 时,除非您使用 Combine 或类似的绑定框架。
标签: ios swift core-data mvvm combine