我有一个脚本,如果数据尚不存在,它会添加到 SwiftData 存储中。对于普通窗口,我已经让逻辑工作了,但我无法让它在 Menu Extra 上工作。以下是示例:
import SwiftUI
import SwiftData
@main
struct XBApp: App {
var bundleID: String = "whatever"
var body: some Scene {
MenuBarExtra("Something", systemImage: "questionmark.bubble") {
// WindowGroup {
VStack {
XBContent(bundleID: bundleID)
.padding(0)
}
.modelContainer(for: XBData.self)
}
}
}
@Model
class XBData {
@Attribute(.unique) var bundle: String
var note: String
init(bundle: String, note: String = "Note") {
self.bundle = bundle
self.note = note
}
}
struct XBList: View {
@Query(sort: \XBData.bundle, animation: .easeInOut) var allXBarData: [XBData]
@Environment(\.modelContext) private var modelContext
var body: some View {
VStack {
Text("Everything So Far …")
List {
ForEach(allXBarData) { xbd in
HStack {
Text(xbd.bundle)
Spacer()
Text(xbd.note)
Spacer()
Button("", systemImage: "trash", action: {
modelContext.delete(xbd)
})
.buttonStyle(.bordered)
}
}
}
}
.modelContainer(for: XBData.self)
}
}
struct XBContent: View {
var bundleID: String = ""
@Environment(\.modelContext) private var modelContext
@State var xBData: XBData?
@Query(sort: \XBData.bundle, animation: .easeInOut) var allXBarData: [XBData]
func loadData(bundleID: String) -> XBData? {
print("\(#fileID):\(#line) - \(bundleID)")
// let filter = FetchDescriptor<XBData>(predicate: #Predicate { $0.bundle == bundleID })
let filter = FetchDescriptor<XBData>(predicate: #Predicate { $0.bundle == bundleID })
do {
var xbd = try modelContext.fetch(filter).first
print("\(#fileID):\(#line) - \(xbd == nil)")
if xbd == nil {
print("\(#fileID):\(#line) - \(xbd!.note)")
xbd = XBData(bundle: bundleID, note: "Newish Note: \(bundleID)")
modelContext.insert(xbd!)
try modelContext.save()
}
else {
print("\(#fileID):\(#line) - \(xbd!.note)")
}
return xbd
} catch {
print("\(#line) oops")
return nil
}
}
init(bundleID: String) {
self.bundleID = bundleID
}
var body: some View {
VStack {
Text(bundleID)
// XBList()
List {
ForEach(allXBarData) { xbd in
HStack {
Text(xbd.bundle)
Spacer()
Text(xbd.note)
Spacer()
Button("", systemImage: "trash", action: {
modelContext.delete(xbd)
})
.buttonStyle(.bordered)
}
}
}
}
.modelContainer(for: XBData.self)
.onAppear {
xBData = loadData(bundleID: bundleID)!
xBData!.note = "Newish Note: \(bundleID)"
try? modelContext.save()
}
}
}
抱歉,样本太长了。
假设 id 为 的项目whatever
不存在,则应该将其添加并显示在列表中。
在 App 结构中,我注释掉了WindowGroup
。如果我切换到它而不是 MenuBarExtra,它会按预期工作。
我还收到了非常有用的信息:
无法找到或解码原因
无法获取或解码不可用的原因
但是,我通过 WindowGroup 或 MenuBarExtra 获得了该信息,因此我不知道它是否相关。
让它与 MenuBarExtra 一起工作的技巧是什么?
尝试使用这种方法
MenuBarExtra
请注意,
func loadData
不要!
在代码中使用,特别是在if xbd == nil { print("\(#fileID):\(#line) - \(xbd!.note)") ...
还要注意,不要
.modelContainer(for: XBData.self)
到处使用,只需使用一个XBApp
就够了。注意,当你这样做时
modelContext.insert(xbd!)
,它会自动获取save
数据,你不必使用try modelContext.save()
编辑-1
这是对我来说非常有效的完整代码,已在 macOS 15 上测试过。