SwiftUI Preview 因 Core Data 'NSInvalidArgumentException' 而崩溃

Posted

技术标签:

【中文标题】SwiftUI Preview 因 Core Data \'NSInvalidArgumentException\' 而崩溃【英文标题】:SwiftUI Preview crashes with Core Data 'NSInvalidArgumentException'SwiftUI Preview 因 Core Data 'NSInvalidArgumentException' 而崩溃 【发布时间】:2022-01-02 11:14:27 【问题描述】:

我的问题是我无法使用 Canvas 预览我的应用的视图,因为我总是收到错误消息:

“由于未捕获的异常而终止应用程序 'NSInvalidArgumentException',原因:'一个 NSManagedObject 类 'App.MPG_A' 必须有一个有效的 NSEntityDescription。"

现在更详细:在我要预览的视图中,我有一个抽象类 MultiplayerGame(MPG A 或 MPG B(子类)的@Binding,而 MultiplayerGame 是 Game 的子类(下图)

评论:MultiplayerGame也是一个抽象实体(如Game)和“Class” -> “MPG B”

当我想通过在 Preview 中创建 moc 对象来预览以下类时,我的应用程序崩溃但我不知道为什么:

    import SwiftUI
import CoreData
import Combine

struct StandingEditView: View 
    
    //multiplayer game with MPG A or MPG B class
    @Binding var game : MultiplayerGame
    
    @State private var invokeFunction : Bool = false
    
    var body: some View 
        
        VStack
            
            List
                
                ForEach(game.players!, id: \.self) player in
                    
                    HStack
                        Text("\(player.name)")
                    
                    
                
                
            
            
            Button(action: 
                invokeFunction.toggle()
            , label: 
                Text("Button")
            )
            
        
        
    


struct StandingEditView_Previews: PreviewProvider 
    
    static let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    
    static var previews: some View 
        
        let game : MultiplayerGame = Standing(context: moc)
        
        let p1 : Player = Player(context: moc)
        let p2 : Player = Player(context: moc)
        let p3 : Player = Player(context: moc)
        
        p1.name =  "Player One"
        p2.name =  "Player Two"
        p3.name =  "Player Three"
        
        game.players = [p1,p2,p3]
        
        return StandingEditView(game: .constant(game))
    

Player 的唯一(非默认)属性是 -> var name : String

我也尝试过使用 AppDelegate,但也没有用...

这个错误一定是因为Preview和moc-Object的原因,因为代码本身会编译,其他的Views都是可见的,没有错误。

感谢您的帮助!

【问题讨论】:

你是怎么得到这张图表的?是定制的解释吗? @swiftPunk 是的,它是为解释而定制的,但是当您更改下方的“编辑器样式”时,您也可以在核心数据库中获得一个 这能回答你的问题吗? PreviewProvider and ObservedObject properties 【参考方案1】:

由于我尝试了所有其他可能性但没有任何帮助,因此我创建了一个新项目并检查了CoreData

然后我在CoreData 文件中创建了主类,并将"ContentView" 中的Item 替换为Game

同样在PersistenceController 中,我用Game 替换了var preview : PersistenceController 下的Item,并使用codegen "Manual/None" 创建了所有类。

现在一切正常。

【讨论】:

【参考方案2】:

您需要为您的上下文设置一个堆栈。 NSManagedObjectContext 必须知道您的模型。

以下StackBuilder 类提供了适合预览的temporary 版本。

private final class StackBuilder 
    
    private let modelName = "Model" // must match your model filename
    
    public enum Configuration 
        case temporary
        case permanent
    
    
    let configuration: Configuration
    
    public init(_ configuration: Configuration = .permanent) 
        self.configuration = configuration
    
    
    public func load() throws -> NSPersistentContainer 
        var errors = [Error]()
        let persistentContainer = NSPersistentContainer(name: modelName)
        persistentContainer.persistentStoreDescriptions = [description(for: configuration)]
        persistentContainer.loadPersistentStores  (value, error) in
            if error != nil 
                errors.append(error!)
            
        
        if errors.count > 0 
            throw errors.first!
        
        return persistentContainer as NSPersistentContainer
    
    
    private func description(for configuration: Configuration) -> NSPersistentStoreDescription 
        let desc = NSPersistentStoreDescription(url: NSPersistentContainer.defaultDirectoryURL())
        switch configuration 
        case .temporary:
            desc.type = NSInMemoryStoreType
        case .permanent:
            desc.shouldInferMappingModelAutomatically = true
            desc.shouldMigrateStoreAutomatically = true
            desc.type = NSSQLiteStoreType
        
        return desc
    

可能需要将上下文作为环境对象传递。

static var previews: some View 
    return StandingEditView(game: .constant(game))
            .environment(\.managedObjectContext, moc)

【讨论】:

我必须在任何地方调用 StackBuilder 类吗?出现相同的错误“NSInvalidArgumentException” - 但项目构建正确,其他视图可见 我是否必须只为“MPG A”之类的模型名称或“MPG A+CoreDataClass”和属性这样做?

以上是关于SwiftUI Preview 因 Core Data 'NSInvalidArgumentException' 而崩溃的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI Preview 因链接器错误而失败

SwiftUI:在 Preview Provider 中执行函数

为啥 macOS 中的 SwiftUI 多行换行文本在 Preview 中有效,但在实际应用中无效?

SwiftUI Preview 未显示(无错误)

Xcode如何利用预览(Preview)让SwiftUI视图快速适配不同尺寸的设备

SwiftUI项目如何在Xcode预览(Preview)中开启调试支持