如何使用 SwiftData 在 macOS 应用程序中打开包含动态数据的新窗口

问题描述 投票:0回答:1

我已经编辑了这个问题,试图使其更清晰,并添加了一个 Xcode 项目

要模拟我试图解决的问题,只需按一个按钮,然后在 macOS 中使用来自 SwiftData 的模型打开一个新窗口。

这是 SwiftDataWindowApp 文件,我试图将 ItemModel 传递给 WindowGroup。我希望只是传递整个模型,因为在其他 SwiftData 应用程序中我从来不需要 Id。

import SwiftUI
import SwiftData

@main
struct SwiftDataWindowApp: App {
   
    var body: some Scene {
        WindowGroup {
            RootView()
                .modelContainer(for: [ItemModel.self])
        }
        
// I can't figure out how to pass an ItemModel to WindowGroup this does not work
       
WindowGroup(for: [ItemModel.self]) { $item in
  ItemView(item:$item)
      .modelContainer(for:[ItemModel.self])
}
        
// Example for WindowGroup documentation
        // A window group that displays messages.
         //WindowGroup(for: Message.ID.self) { $messageID in
             //MessageDetail(messageID: messageID)
        // }
        
    }
}

在 ItemsButtonView 文件中是我调用 openWindow 的地方

import SwiftUI

struct ItemsButtonView: View {
    @Environment(\.openWindow) private var openWindow
    let item: ItemModel
  
    
    var body: some View {
        NavigationStack {
            VStack(alignment: .leading) {
                Text("\(item.name )")
                Text("\(item.desc )")
                Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))")
                
                HStack {
                    Text("Open Item In New Window")
                        .onTapGesture {
                            // Open Item in new window
                           // openWindow(value: item)
                           print("Open Item Button Presed")
                        }
                }
            }  
        }
    }
}


我的模型

import Foundation
import SwiftData

@Model
final class ItemModel {
    var timestamp: Date
    var name: String
    var desc: String
    
    
    init(timestamp: Date, name: String = "", desc: String = "") {
        self.timestamp = timestamp
        self.name = name
        self.desc = desc
    }
}

我想在新窗口中打开的ItemView文件。

import SwiftUI

struct ItemView: View {
    let item: ItemModel
    var body: some View {
        
        VStack{
            Text("Name: \(item.name)")
            Text("Description: \(item.desc)")
            Text("Date: \(item.timestamp)")
        }
        .frame(width:600, height:300)
    }
}


swift xcode macos swiftui swift-data
1个回答
0
投票

首先,我认为在这种情况下最好为 ModelContainer 拥有一个属性,而不是为每个 WindowGroup 创建一个新属性

以下示例来自 SwiftData 项目的 Xcode 模板。

var sharedModelContainer: ModelContainer = {
    let schema = Schema([ItemModel.self])
    let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)

    do {
        return try ModelContainer(for: schema, configurations: [modelConfiguration])
    } catch {
        fatalError("Could not create ModelContainer: \(error)")
    }
}()

然后你有一个奇怪的 WindowGroup 类型,一个模型类型的数组。由于您只会将一个对象传递给 openWindow,然后传递给视图,因此它不能是数组,而且使用的类型必须符合 Codable,因此模型类型不是一个好主意,最好使用模型的 ID 类型

WindowGroup(for: ItemModel.ID.self)

然后有不同的方法来处理我们得到的ID值,在下面的解决方案中我直接将其解包并加载模型对象,然后将其传递给视图

let context = ModelContext(sharedModelContainer)
if let id, let model = context.model(for: id) as? ItemModel {
    ItemView(item: model)
}

场景的完整代码

var body: some Scene {
    WindowGroup {
        RootView()
    }
    .modelContainer(sharedModelContainer)

    WindowGroup(for: ItemModel.ID.self) { $id in
        let context = ModelContext(sharedModelContainer)
        if let id, let model = context.model(for: id) as? ItemModel {
            ItemView(item: model)
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.