切换选项卡后 UI 会随 ObservableObject 发生变化
Posted
技术标签:
【中文标题】切换选项卡后 UI 会随 ObservableObject 发生变化【英文标题】:UI changes with ObservableObject just after switching tabs 【发布时间】:2020-03-17 21:59:03 【问题描述】:我有一个ObservableObject
,用于在从服务器发送新数据时更新我的 UI(一个包含自定义结构数组的类)。
由于某种原因,发送数据时,ContentView
的body
被调用,但数据没有改变。我什至添加了一个print
语句来检查数组包含的数据是否正确。
当我尝试切换到 TabView
上的另一个选项卡,然后切换回主视图时,UI确实会更新。有人知道为什么 UI 会在我切换标签时更新,尽管 body
会在数据更改时被召回以更新 UI?
主视图
struct HomeView: View
@ObservedObject private var fbData = firebaseData
var body: some View
TabView
//Home Tab
NavigationView
ScrollView(showsIndicators: false)
ForEach(self.fbData.posts.indices, id: \.self) postIndex in
PostView(post: self.$fbData.posts[postIndex])
.listRowInsets(EdgeInsets())
.padding(.vertical, 5)
.navigationBarTitle("MyPhotoApp", displayMode: .inline)
.navigationBarItems(leading:
Button(action:
print("Camera btn pressed")
, label:
Image(systemName: "camera")
.font(.title)
)
, trailing:
Button(action:
print("Messages btn pressed")
, label:
Image(systemName: "paperplane")
.font(.title)
)
)
. tabItem(
Image(systemName: "house")
.font(.title)
)
Text("Search").tabItem
Image(systemName: "magnifyingglass")
.font(.title)
Text("Upload").tabItem
Image(systemName: "plus.app")
.font(.title)
Text("Activity").tabItem
Image(systemName: "heart")
.font(.title)
Text("Profile").tabItem
Image(systemName: "person")
.font(.title)
.accentColor(.black)
.edgesIgnoringSafeArea(.top)
FirebaseData:
class FirebaseData : ObservableObject
@Published var posts = [Post]()
let postsCollection = Firestore.firestore().collection("Posts")
init()
self.fetchPosts()
//MARK: Fetch Data
private func fetchPosts()
self.postsCollection.addSnapshotListener (documentSnapshot, err) in
if err != nil
print("Error fetching posts: \(err!.localizedDescription)")
return
else
documentSnapshot!.documentChanges.forEach diff in
if diff.type == .added
let post = self.createPostFromDocument(document: diff.document)
self.posts.append(post)
else if diff.type == .modified
self.posts = self.posts.map (post) -> Post in
if post.id == diff.document.documentID
return self.createPostFromDocument(document: diff.document)
else
return post
else if diff.type == .removed
for index in self.posts.indices
if self.posts[index].id == diff.document.documentID
self.posts.remove(at: index)
【问题讨论】:
你能发布更多关于 ObservableObject 如何链接到 ContentView 的代码吗? 检查 ***.com/questions/60727556/… 并尝试了解 SwiftUI 如何知道要“刷新”、“重新加载”...等内容。您的数据和视图之间的关系是通过 '@State' 或 '@ ObservedObject 的属性包装器。 View 观察 State 或 ObservedObject 的内部,如果看到一些变化,它会重新评估其主体。仅此而已,背后没有奇迹。带有大量 .padding、.font .... 等的代码根本没有帮助。 @denis_lor 谢谢。我已经用更多信息更新了我的问题。 @user3441734 谢谢。我知道属性包装器是如何工作的,body
甚至可以正确回忆,但由于某种原因,只是 UI 本身没有改变。我已经添加了更多信息,如果你能看一下,我会很高兴
请发布您的 ObservableObject,这可能是问题的关键部分。
【参考方案1】:
您的代码示例无助于查找错误。最后我知道了如何演示它。首先,以“正确的方式”进行(复制-粘贴-自己尝试)
import SwiftUI
struct Data: Identifiable
let id = UUID()
let text: String
class Model: ObservableObject
@Published var data: [Data] = [Data(text: "alfa"), Data(text: "beta")]
struct ContentView: View
@ObservedObject var model = Model()
var body: some View
TabView
View1(model: model).tabItem
Text("View 1")
View2(model: model).tabItem
Text("View 2")
struct View1: View
@ObservedObject var model: Model
var body: some View
VStack
Text("View 1").font(.largeTitle)
DataView(data: model.data)
Button(action:
self.model.data.append(Data(text: String("ABCDEFGH".shuffled())))
)
Text("Add random data")
struct View2: View
@ObservedObject var model: Model
var body: some View
VStack
Text("View 2").font(.largeTitle)
DataView(data: model.data.filter( (item) -> Bool in
item.text.count < 4
))
// to distinguish from other DataView !! it seems to be a bug in SwiftUI
// try to remove it to see the difference
.id("view2")
Button(action:
self.model.data.append(Data(text: String("ABC".shuffled())))
)
Text("Add random data")
struct DataView: View
var data: [Data]
var body: some View
List
ForEach(data) (item) in
Text(item.text)
struct ContentView_Previews: PreviewProvider
static var previews: some View
ContentView()
我按原样工作,您可以修改每个选项卡中的数据,看到刷新的数据等。
移除“固定 - 用户定义” .id 修饰符,它会显着改变行为
这看起来像是 SwiftUI 中的一个严重错误 ...
【讨论】:
我想你不明白我所说的“当我尝试切换到 TabView 上的另一个选项卡,然后切换回主视图时,UI 确实会更新”的意思。我不想在 Tab1 到 Tab2 之间传递信息。posts
数组应该在 tab1 中。但由于某种原因,tab1 没有得到更新,就在我切换到 tab2(它只有一个 text
标题,仅此而已)并切换回 tab1 时,信息更新。您发布的代码类似于我的代码,但添加了另一个选项卡。所以不幸的是它不起作用。还有其他想法吗?
在您发布一些最小的“工作”示例之前,我很抱歉……我在上面发布的是真正的错误,很难识别。我把它留给别人了……
请在此处查看我更新的问题以及更多详细信息和代码:***.com/questions/60740197/…【参考方案2】:
我认为是 SwiftUI 错误。我这样解决这个问题。 而不是渲染你的 PostView(post: self.$fbData.posts[postIndex]) 在 ForEach 中实现 post 视图。
ForEach(self.fbData.posts.indices, id: \.self) postIndex in
Text(self.$fbData.posts[postIndex].comment)
Text(self.$fbData.posts[postIndex].date)
....
【讨论】:
以上是关于切换选项卡后 UI 会随 ObservableObject 发生变化的主要内容,如果未能解决你的问题,请参考以下文章
android中的tabHost怎样在点击一个选项卡后跳转到一个activity,点击另一个选项卡跳转到另一个activity?