背景
我想要一个视图,将允许用户创建一个新的核心数据项.该项目将具有到另一个核心数据项目的链接,用户将从选取器中 Select 该核心数据项目,该选取器将预先填充在视图第一次加载时 Select 的默认项目(与该用户最相关的项目).
##问题
但是,当我在.onspecar(in the actual code it's a modified version on .onAppear that only runs the code the first time .onAppear shows but that's good enough for this question)期间更改选取器的"Selection"变量时,它不会更改选取器的选定值.
如果我再次更改它,比如使用运行相同 Select 代码的按钮,它确实会更改选取器.
另外,如果我添加引用选取器的 Select 变量的内容(它是@State.参见示例代码)它可以完美地工作!
如何复制这一问题
要复制在Xcode(14.3)中创建新项目的问题,请 Select App
并勾选Use Core Data
.
现在用以下代码替换整个ContentView
:
import SwiftUI
import CoreData
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: []
) var items: FetchedResults<Item>
@State private var selectedItem: Item?
var body: some View {
Form {
// ---------------------------------------------
// Uncommenting the next line fixes the pickers!
//let _ = selectedItem
// ---------------------------------------------
Picker ("Part of Item Session", selection: $selectedItem) {
Text("New Item").tag(nil as Item?)
ForEach(items) { item in
Text("\(item.timestamp!.description)").tag(item as Item?)
}
}
Button {
ContentView.addItems(withViewContext: viewContext)
} label: {
Text("Add Items")
}
Button {
selectedItem = ContentView.getItem(withViewContext: viewContext)
} label: {
Text("Select Random Item")
}
Button {
if (selectedItem != nil) {
print("Item: \(String(describing: selectedItem!.timestamp))")
} else {
print("Item is nil!")
}
} label: {
Text("View Item (print to console)")
}
}
.onAppear {
selectedItem = ContentView.getItem(withViewContext: viewContext)
if (selectedItem != nil) {
print("Item: \(String(describing: selectedItem!.timestamp))")
} else {
print("Item is nil!")
}
}
}
static func addItems(withViewContext viewContext: NSManagedObjectContext) {
for _ in 0..<10 {
let newItem = Item(context: viewContext)
newItem.timestamp = Date().addingTimeInterval(-Double(Int.random(in: 1..<5000)))
}
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
static func getItem(withViewContext viewContext: NSManagedObjectContext) -> Item? {
let fetchRequest: NSFetchRequest<Item> = Item.fetchRequest()
fetchRequest.sortDescriptors = []
var items: [Item] = []
do {
// Fetch
items = try viewContext.fetch(fetchRequest)
// Pick a random(ish) item
if (items.count > 0) {
let randomInt = Int.random(in: 0..<items.count)
print("Setting Item: '\(items[randomInt].timestamp!.description)'")
// Return the random(ish) item
return items[randomInt]
}
} catch {
print("Unable to Fetch Item, (\(error))")
}
return nil
}
}
然后:
- 在
iPhone 14 Pro Max
模拟器中运行该项目 - 单击
Add Items
按钮将一些示例添加到您的数据库 - 从Xcode中重新运行模拟器中的应用程序以重新启动它,您将看到选取器仍然 Select 了
New Item
,但如果您单击View Item ...
按钮,它将打印 Select 的实际值,而不是nil
(New Item
的值)! - 如果您更改 Select 使用
Select Random Item
(它只是为拾取器 Select 另一个随机项目),它将正确地更改拾取器.
此外,如果您:
- 再次重新启动应用程序
- 点击
View Item
按钮 - 从控制台中打印的选取器中 Select 相同的项目,它不会更改选取器.
- 但是,如果您将选取器更改为任何其他项目,它将更改选取器!
修复它的奇怪的黑客
为了看到选取器按我预期的那样工作,取消对第let _ = selectedItem
行(第17行)的注释并重新运行应用程序……现在,选取器立刻是正确的!
问题
这是怎么回事.是SWIFT的漏洞,还是我做错了什么?