开发者社区 问答 正文

FetchedResults崩溃:调度队列:com.apple.main-thread(0)

我遵循本教程学习动态过滤器和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?代码有什么问题?

展开
收起
游客5akardh5cojhg 2019-12-24 12:58:06 1372 分享 版权
阿里云 AI 助理回答

根据你提供的信息,崩溃可能是因为在预览环境中尝试访问@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)
    }
}

这样设置后,你的预览应该能够成功显示而不引发崩溃了。

有帮助
无帮助
AI 助理回答生成答案可能存在不准确,仅供参考
0 条回答
写回答
取消 提交回答
问答分类:
问答地址: