我遵循本教程学习动态过滤器和CoreData:https://www.hackingwithswift.com/quick-start/ios-swiftui/dynamically-filtering-fetchrequest-with-swiftui
我有以下代码。ContentView.swift:
import SwiftUI
struct ContentView: View {
@Environment(\.managedObjectContext) var moc
@State var lastNameFilter = "A"
var body: some View {
VStack {
FilteredList(filter: lastNameFilter)
Button("Add Examples") {
let taylor = Singer(context: self.moc)
taylor.firstName = "Taylor"
taylor.lastName = "Swift"
let ed = Singer(context: self.moc)
ed.firstName = "Ed"
ed.lastName = "Sheeran"
let adele = Singer(context: self.moc)
adele.firstName = "Adele"
adele.lastName = "Adkins"
try? self.moc.save()
}
Button("Show A") {
self.lastNameFilter = "A"
}
Button("Show S") {
self.lastNameFilter = "S"
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
FilteredList.swift:
import CoreData
import SwiftUI
struct FilteredList: View {
var fetchRequest: FetchRequest<Singer>
var singers: FetchedResults<Singer> { fetchRequest.wrappedValue }
var body: some View {
List(singers, id: \.self) { singer in
Text("\(singer.wrappedFirstName) \(singer.wrappedLastName)")
}
}
init(filter: String) {
fetchRequest = FetchRequest<Singer>(entity: Singer.entity(), sortDescriptors: [], predicate: NSPredicate(format: "lastName BEGINSWITH %@", filter))
}
}
//struct FilteredList_Previews: PreviewProvider {
// static var previews: some View {
// }
//}
歌手+CoreDataClass.斯威夫特:
import Foundation
import CoreData
@objc(Singer)
public class Singer: NSManagedObject {
}
歌手+CoreDataProperties.Swive:
import Foundation
import CoreData
extension Singer {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Singer> {
return NSFetchRequest<Singer>(entityName: "Singer")
}
@NSManaged public var firstName: String?
@NSManaged public var lastName: String?
var wrappedFirstName : String {
firstName ?? "Unknown"
}
var wrappedLastName : String {
lastName ?? "Unknown"
}
} 核心数据有一个实体:具有两个字符串属性的歌手:FirstName和LastName。模块:当前产品模块。手册/无。
当我尝试预览内容视图时,预览崩溃。当我打开崩溃日志文件并转到DebugNavigator时,我可以看到以下错误:
分派队列:com.apple.main-线程(0)
在线:
FilteredList.swift:
var singers: FetchedResults<Singer> { fetchRequest.wrappedValue }
List(singers, id: \.self) { singer in
AppDelegate.swift:
class AppDelegate: UIResponder, UIApplicationDelegate {
会有什么问题呢?WrappedValue?代码有什么问题?
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
根据你提供的信息,崩溃可能是因为在预览环境中尝试访问@FetchRequest
的.wrappedValue
时,CoreData上下文还未就绪。SwiftUI的预览功能运行在一个没有实际持久化存储环境的上下文中,因此它无法像在真实应用运行时那样与CoreData交互。
为了解决这个问题,你需要确保在预览模式下不依赖于真实的CoreData操作。可以通过条件编译来实现这一点,让预览时使用静态数据而非执行真正的数据库查询。
修改FilteredList.swift
中的init
方法,加入对预览的支持:
init(filter: String) {
#if DEBUG
// 预览环境下使用静态数据
let taylor = Singer(context: InMemoryContext.shared)
taylor.firstName = "Taylor"
taylor.lastName = "Swift"
let ed = Singer(context: InMemoryContext.shared)
ed.firstName = "Ed"
ed.lastName = "Sheeran"
let adele = Singer(context: InMemoryContext.shared)
adele.firstName = "Adele"
adele.lastName = "Adkins"
singers = [taylor, ed, adele]
#else
// 正常环境下使用FetchRequest
fetchRequest = FetchRequest(entity: Singer.entity(), sortDescriptors: [], predicate: NSPredicate(format: "lastName BEGINSWITH %@", filter))
#endif
}
// 添加一个用于预览的内存中NSManagedObjectContext
class InMemoryContext: NSManagedObjectContext {
static let shared = InMemoryContext()
override init() {
super.init(concurrencyType: .mainQueueConcurrencyType)
let mom = NSManagedObjectModel.mergedModel(from: nil)!
self.persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: mom)
do {
try self.persistentStoreCoordinator.addPersistentStore(ofType: NSInMemoryStoreType, configurationName: nil, at: nil, options: nil)
} catch {
fatalError("Failed to initialize in-memory store: \(error)")
}
}
}
这段代码创建了一个InMemoryContext
类,它被用作预览时的数据源,这样就可以在不连接到实际数据库的情况下提供数据给预览。同时,通过#if DEBUG ... #else ... #endif
预处理器指令,我们使得在预览环境下使用这个内存上下文和静态数据,而在正常运行时则使用正常的FetchRequest
。
记得在ContentView_Previews
中也要做相应的调整,以确保使用模拟数据进行预览:
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environment(\.managedObjectContext, InMemoryContext.shared)
}
}
这样设置后,你的预览应该能够成功显示而不引发崩溃了。