SwiftUI - 在同一结构中使用@ObservedObject 作为@FetchRequest 的结果来强制更新UI
SwiftUI - Using an @ObservedObject for the result of an @FetchRequest in the same struct to force-update the UI
据我所知,我将核心数据实体对象传递给子结构中的@ObservedObject,以在我更改核心数据对象时强制 UI 进行更新。
示例:
struct ParentView: View {
@FetchRequest(entity: CDUser.entity(), sortDescriptors: [])
var users: FetchedResults<CDUser>
var body: some View {
List {
ForEach(users, id: \.self) { item in
ChildView(item: item)
}
}
}
}
struct ChildView: View {
@Environment(\.managedObjectContext) private var moc
@ObservedObject var item: CDUser
var body: some View {
HStack {
Button(action: {
item.count = item.count + 1
do {
try moc.save()
} catch {
print(error)
}
}, label: {
Text(String(item.count))
}
)
}
}
}
当按下按钮时,@ObservedObject 将强制 UI 显示增加的 item.count。
虽然这很好用,但有没有办法通过在同一结构中同时使用 @FetchRequest 和 @ObservedObject 来不使用父子层次结构来强制执行 UI 更新?
理想情况下,我只有一个结构,其中包含按钮。
下面的示例将更新代码数据对象,但更改只会在视图重新出现时反映在 UI 中。
示例:
struct MainView: View {
@Environment(\.managedObjectContext) private var moc
@FetchRequest(entity: CDUser.entity(), sortDescriptors: [])
var users: FetchedResults<CDUser>
// HOW DO I INTEGRATE THIS OBSERVED OBJECT TO REFLECT THE BUTTON ACTION IMMEDIATELY IN THE UI?
// @ObservedObject var users: [CDUser]
//
var body: some View {
List {
ForEach(users, id: \.self) { item in
Button(action: {
item.count = item.count + 1
do {
try moc.save()
} catch {
print(error)
}
}, label: {
Text(String(item.count))
}
)
}
}
}
}
编辑:添加一个更复杂的示例,其中将按钮更改为子视图不会导致部分更新:
struct MainView: View {
@Environment(\.managedObjectContext) private var moc
@FetchRequest(entity: CDUser.entity(), sortDescriptors: [])
var users: FetchedResults<CDUser>
var body: some View {
List {
//Section of logged-in users
Section(header: Text("Logged in")) {
ForEach(users.filter({ [=13=].logged == true }), id: \.self) { user in
Button(action: {
user.logged = false
do {
try moc.save()
} catch {
print(error)
}
}, label: {
Text(String(user.firstName))
})
}
//Section of logged-out users
Section(header: Text("Logged out")) {
ForEach(users.filter({ [=13=].logged == false }), id: \.self) { user in
Button(action: {
user.logged = true
do {
try moc.save()
} catch {
print(error)
}
}, label: {
Text(String(user.firstName))
})
}
}
}
}
}
}
你不能那样做。因为数组不是 ObservableObject
。制作一个 CDUserButtonView
以便您可以观察循环中的项目
您添加的部分不会更新,因为您应该使用 NSPredicate
而不是没有任何内置观察器的 filter
,这是预期的行为,FetchResults
仅当整个数组发生变化时才导致重绘。数组不能作为观察对象只能单独观察数组的元素。
此外,如果您的目标是 iOS 15+,您应该查看 SectionedFetchRequest
它会为您创建这些部分。
https://developer.apple.com/wwdc21/10017
大约在 23:26
分钟
据我所知,我将核心数据实体对象传递给子结构中的@ObservedObject,以在我更改核心数据对象时强制 UI 进行更新。
示例:
struct ParentView: View {
@FetchRequest(entity: CDUser.entity(), sortDescriptors: [])
var users: FetchedResults<CDUser>
var body: some View {
List {
ForEach(users, id: \.self) { item in
ChildView(item: item)
}
}
}
}
struct ChildView: View {
@Environment(\.managedObjectContext) private var moc
@ObservedObject var item: CDUser
var body: some View {
HStack {
Button(action: {
item.count = item.count + 1
do {
try moc.save()
} catch {
print(error)
}
}, label: {
Text(String(item.count))
}
)
}
}
}
当按下按钮时,@ObservedObject 将强制 UI 显示增加的 item.count。
虽然这很好用,但有没有办法通过在同一结构中同时使用 @FetchRequest 和 @ObservedObject 来不使用父子层次结构来强制执行 UI 更新?
理想情况下,我只有一个结构,其中包含按钮。
下面的示例将更新代码数据对象,但更改只会在视图重新出现时反映在 UI 中。
示例:
struct MainView: View {
@Environment(\.managedObjectContext) private var moc
@FetchRequest(entity: CDUser.entity(), sortDescriptors: [])
var users: FetchedResults<CDUser>
// HOW DO I INTEGRATE THIS OBSERVED OBJECT TO REFLECT THE BUTTON ACTION IMMEDIATELY IN THE UI?
// @ObservedObject var users: [CDUser]
//
var body: some View {
List {
ForEach(users, id: \.self) { item in
Button(action: {
item.count = item.count + 1
do {
try moc.save()
} catch {
print(error)
}
}, label: {
Text(String(item.count))
}
)
}
}
}
}
编辑:添加一个更复杂的示例,其中将按钮更改为子视图不会导致部分更新:
struct MainView: View {
@Environment(\.managedObjectContext) private var moc
@FetchRequest(entity: CDUser.entity(), sortDescriptors: [])
var users: FetchedResults<CDUser>
var body: some View {
List {
//Section of logged-in users
Section(header: Text("Logged in")) {
ForEach(users.filter({ [=13=].logged == true }), id: \.self) { user in
Button(action: {
user.logged = false
do {
try moc.save()
} catch {
print(error)
}
}, label: {
Text(String(user.firstName))
})
}
//Section of logged-out users
Section(header: Text("Logged out")) {
ForEach(users.filter({ [=13=].logged == false }), id: \.self) { user in
Button(action: {
user.logged = true
do {
try moc.save()
} catch {
print(error)
}
}, label: {
Text(String(user.firstName))
})
}
}
}
}
}
}
你不能那样做。因为数组不是 ObservableObject
。制作一个 CDUserButtonView
以便您可以观察循环中的项目
您添加的部分不会更新,因为您应该使用 NSPredicate
而不是没有任何内置观察器的 filter
,这是预期的行为,FetchResults
仅当整个数组发生变化时才导致重绘。数组不能作为观察对象只能单独观察数组的元素。
此外,如果您的目标是 iOS 15+,您应该查看 SectionedFetchRequest
它会为您创建这些部分。
https://developer.apple.com/wwdc21/10017
大约在 23:26
分钟