BLACK FRIDAY: Save 50% on all my Swift books and bundles! >>

SOLVED: How to open a new WindowGroup with a SwiftData model in macOS

Forums > SwiftUI

I have have edited this question to try to make it more clear and added an Xcode project

To simultate the problem I am trying to solve which is just press a button and open a new window in macOS with a model from SwiftData.

Here is the SwiftDataWindowApp file where I am trying to pass an ItemModel to WindowGroup. I am hoping just to pass the whole model becuase in other SwiftData applications I have never needed an 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)
        // }

    }
}

In ItemsButtonView file is where I am calling 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")
                        }
                }
            }  
        }
    }
}

My model

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 file that I want opened in new window.

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)
    }
}

1      

As me less knowledge the solution to open a new window with your Trade model in SwiftUI using SwiftData:

The issue with your code is that openWindow expects an Identifiable value, and Trade itself might not be directly identifiable.

Here's how to fix it:

Use trade.id: Since Trade conforms to Identifiable, you can directly pass trade.id to openWindow.

Swift TradeView: View { // ... HStack { Text("Open Trade") .onTapGesture { openWindow(value: trade.id) // Pass the trade's id } } } Use code with caution. content_copy WindowGroup with for clause: Adjust the WindowGroup to use Trade.id for identification:

Swift WindowGroup(for: Trade.ID.self) { tradeID in TradeView(trade: fetchTrade(with: tradeID)) // Fetch trade based on ID .modelContainer(for: [Trade.self]) } Use code with caution. content_copy This approach defines the window group for Trade.ID which is an Identifiable type. Inside the closure, you can fetch the complete Trade object using the provided tradeID.

Fetching Trade based on ID:

You'll need to implement a function to fetch the Trade object based on the provided tradeID. This depends on your specific data access layer. Here's an example assuming you have a function to fetch by ID:

Swift func fetchTrade(with id: Trade.ID) -> Trade { // Implement your logic to fetch Trade with the provided ID // This could involve using SwiftData's persistence layer return Trade() // Replace with fetched Trade object } Use code with caution. content_copy Remember to replace Trade() with the actual fetched Trade object.

This approach allows you to open a new window with the complete Trade data accessible in the TradeView within the second WindowGroup.

   

Here is a solution I got from my Stackoverflow question thought I would share it here.

import SwiftUI
import SwiftData

@main
struct SwiftDataWindowApp: App {

    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)")
        }
    }()

    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)
            }
        }
    }
}

1      

Save 50% in my WWDC sale.

SAVE 50% All our books and bundles are half price for Black Friday, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.