SwiftUI:UI在 @Published 变量更改时未更新

huangapple go评论89阅读模式
英文:

SwiftUI: UI does not update on @Published var change

问题

这是你提供的代码的翻译部分:

模型:

  1. struct Post: Identifiable{
  2. var id = UUID().uuidString
  3. var postImage: String
  4. var title: String
  5. var description: String
  6. var starRating: Int
  7. var numberOfRatings : Int
  8. var postRating : Double
  9. var postDuration : Int
  10. var postLanguage : String
  11. var publishedBy : String
  12. var publishedYear : Int
  13. var isLiked : Bool
  14. var author : String
  15. }
  16. class DataStore: ObservableObject {
  17. @Published var posts = [
  18. Post(postImage: "post1", title: "Black Widow", description: "some description", starRating: 4, numberOfRatings: 251, postRating: 7.1, postDuration: 134, postLanguage: "English", publishedBy: "Alina", publishedYear: 2001, isLiked: false, author: "someAuthor1"),
  19. ]
  20. func togglePostLike(post: Post) {
  21. if let index = posts.firstIndex(where: { $0.id == post.id }) {
  22. posts[index].isLiked.toggle()
  23. }
  24. }
  25. }

视图:

  1. struct play: View {
  2. @State var selectedPost : Post?
  3. @EnvironmentObject private var dataStore : DataStore
  4. @State var switchView = false
  5. var body: some View {
  6. if switchView == false {
  7. // 在迭代中,我称每个元素为 "post"
  8. Image(systemName: post.isLiked ? "heart.fill" : "heart")
  9. .font(.system(size: 30))
  10. .foregroundColor(.red)
  11. .offset(x: 100, y: 150)
  12. .onTapGesture {
  13. if post.isLiked == true {
  14. dataStore.togglePostLike(post: post)
  15. let removeFromFavorite = Album(title: post.title, author: post.author, postImage: post.postImage)
  16. if let index = dataStore.albums.firstIndex(of: removeFromFavorite) {
  17. dataStore.albums.remove(at: index)
  18. }
  19. } else {
  20. dataStore.togglePostLike(post: post)
  21. let addToFavorite = Album(title: post.title, author: post.author, postImage: post.postImage)
  22. dataStore.albums.append(addToFavorite)
  23. }
  24. }
  25. // 迭代所有的帖子,然后将 "selectedPost" 的值设置为点击的帖子
  26. ForEach(dataStore.posts, id:\.id) {post in
  27. Image("\(post.postImage)")
  28. .onTapGesture {
  29. selectedPost = post
  30. switchView = true
  31. }
  32. }
  33. switchView = true
  34. } else {
  35. NewView(selectedPost: selectedPost!)
  36. .environmentObject(dataStore)
  37. }
  38. }
  39. }
  40. struct NewView: View {
  41. @EnvironmentObject private var dataStore : DataStore
  42. var selectedPost : Post
  43. var body: some View {
  44. VStack {
  45. Text(String(selectedPost.isLiked))
  46. if selectedPost.isLiked {
  47. Circle()
  48. .foregroundColor(.red)
  49. .frame(width: 50, height: 50, alignment: .center)
  50. .foregroundColor(.black)
  51. .overlay(
  52. Image(systemName: "heart")
  53. .font(.system(size: 25))
  54. .foregroundColor(.white)
  55. )
  56. Text("Save")
  57. } else {
  58. Circle()
  59. .strokeBorder(.black, lineWidth: 2.5)
  60. .frame(width: 50, height: 50, alignment: .center)
  61. .foregroundColor(.black)
  62. .overlay(
  63. Image(systemName: "heart")
  64. .font(.system(size: 25))
  65. .foregroundColor(.black)
  66. )
  67. Text("Save")
  68. }
  69. }
  70. .onTapGesture {
  71. dataStore.togglePostLike(post: selectedPost)
  72. if selectedPost.isLiked == true {
  73. let removeFromFavorite = Album(title: selectedPost.title, author: selectedPost.author, postImage: selectedPost.postImage)
  74. if let index = dataStore.albums.firstIndex(of: removeFromFavorite) {
  75. dataStore.albums.remove(at: index)
  76. }
  77. } else {
  78. let addToFavorite = Album(title: selectedPost.title, author: selectedPost.author, postImage: selectedPost.postImage)
  79. dataStore.albums.append(addToFavorite)
  80. }
  81. }
  82. }
  83. }

请注意,代码中可能存在一些 HTML 编码(例如 ")或未定义的变量(例如 postAlbum),你需要根据实际情况进行调整。

英文:

So I have this model, and for simplicity I have only included one element in the posts variable. In my view I am displaying all the elements in the array and when an element is clicked, the view changes to only display information about that one post.

In this new view I have a button that indicates wether the isLiked value in the model is liked or not. I toggle between the states by using the togglePostLike function in the class.

If isLiked == false the button should have no color, and be red if it its true. The problem is that the UI doesn’t update the color / isLiked value immediately.
I also have the same functionality somewhere else in my code, but there it updates just fine.

How can I solve this?

Model:

  1. struct Post: Identifiable{
  2. var id = UUID().uuidString
  3. var postImage: String
  4. var title: String
  5. var description: String
  6. var starRating: Int
  7. var numberOfRatings : Int
  8. var postRating : Double
  9. var postDuration : Int
  10. var postLanguage : String
  11. var publishedBy : String
  12. var publishedYear : Int
  13. var isLiked : Bool
  14. var author : String
  15. }
  16. class DataStore: ObservableObject {
  17. @Published var posts = [
  18. Post(postImage: "post1", title: "Black Widow", description: "some description", starRating: 4, numberOfRatings: 251, postRating: 7.1, postDuration: 134, postLanguage: "English", publishedBy: "Alina", publishedYear: 2001, isLiked: false, author: "someAuthor1"),
  19. ]
  20. func togglePostLike(post: Post) {
  21. if let index = posts.firstIndex(where: { $0.id == post.id }) {
  22. posts[index].isLiked.toggle()
  23. }
  24. }
  25. }

View
UPDATED VIEW
UPDATED VIEW 2

I have added a code block to show how I use dataStore and display the posts.

  1. This update is to show how the two view work together.
  2. struct play: View {
  3. @State var selectedPost : Post?
  4. @EnvironmentObject private var dataStore : DataStore
  5. @State var switchView = false
  6. var body: some View {
  7. if switchView == false {
  8. // When iterating I call each element "post"
  9. Image(systemName: post.isLiked ? "heart.fill" : "heart")
  10. .font(.system(size: 30))
  11. .foregroundColor(.red)
  12. .offset(x: 100, y: 150)
  13. .onTapGesture {
  14. if post.isLiked == true {
  15. dataStore.togglePostLike(post: post)
  16. let removeFromFavorite = Album(title: post.title, author: post.author, postImage: post.postImage)
  17. if let index = dataStore.albums.firstIndex(of: removeFromFavorite) {
  18. dataStore.albums.remove(at: index)
  19. }
  20. } else {
  21. dataStore.togglePostLike(post: post)
  22. let addToFavorite = Album(title: post.title, author: post.author, postImage: post.postImage)
  23. dataStore.albums.append(addToFavorite)
  24. }
  25. }
  26. // Iterate all the posts and then give "selectedPost" the value of the clicked post
  27. ForEach(dataStore.posts, id:\.id) {post in
  28. Image("\(post.postImage)")
  29. .onTapGesture {
  30. selectedPost = post
  31. switchView = true
  32. }
  33. }
  34. switchView = true
  35. } else {
  36. NewView(selectedPost: selectedPost!)
  37. .environmentObject(dataStore)
  38. }
  39. }
  40. }
  41. struct NewView: View {
  42. @EnvironmentObject private var dataStore : DataStore
  43. var selectedPost : Post
  44. var body: some View {
  45. VStack {
  46. Text(String(selectedPost.isLiked))
  47. if selectedPost.isLiked {
  48. Circle()
  49. .foregroundColor(.red)
  50. .frame(width: 50, height: 50, alignment: .center)
  51. .foregroundColor(.black)
  52. .overlay(
  53. Image(systemName: "heart")
  54. .font(.system(size: 25))
  55. .foregroundColor(.white)
  56. )
  57. Text("Save")
  58. } else {
  59. Circle()
  60. .strokeBorder(.black, lineWidth: 2.5)
  61. .frame(width: 50, height: 50, alignment: .center)
  62. .foregroundColor(.black)
  63. .overlay(
  64. Image(systemName: "heart")
  65. .font(.system(size: 25))
  66. .foregroundColor(.black)
  67. )
  68. Text("Save")
  69. }
  70. }
  71. .onTapGesture {
  72. dataStore.togglePostLike(post: selectedPost)
  73. if selectedPost.isLiked == true {
  74. let removeFromFavorite = Album(title: selectedPost.title, author: selectedPost.author, postImage: selectedPost.postImage)
  75. if let index = dataStore.albums.firstIndex(of: removeFromFavorite) {
  76. dataStore.albums.remove(at: index)
  77. }
  78. } else {
  79. let addToFavorite = Album(title: selectedPost.title, author: selectedPost.author, postImage: selectedPost.postImage)
  80. dataStore.albums.append(addToFavorite)
  81. }
  82. }
  83. }
  84. }

答案1

得分: 0

I am answering my own question here, but I can’t really explain the "why's" so feel free to add a comment with further explanation to my post.

我在这里回答自己的问题,但我无法真正解释 "为什么",所以请随时在我的帖子下添加进一步的解释评论。

I managed to fix the problem by changing var selectedPost : Post to a @Binding, as such: @Binding var selectedPost : Post.

我成功修复了问题,方法是将 var selectedPost : Post 更改为 @Binding var selectedPost : Post

I then also changed the .onTapGesture in the NewView to this:

然后我还将NewView中的.onTapGesture 更改为以下内容:

英文:

I am answering my own question here, but I can’t really explain the "why´s" so feel free to add a comment with further explanation to my post.

I managed to fix the problem by changing var selectedPost : Post to a @Binding, as such: @Binding var selectedPost : Post.

I then also changed the .onTapGesture in the NewView to this:

  1. .onTapGesture {
  2. dataStore.togglePostLike(post: selectedPost)
  3. if selectedPost.isLiked == true {
  4. // This line is new
  5. selectedPost.isLiked = false
  6. let removeFromFavorite = Album(title: selectedPost.title, author: selectedPost.author, postImage: selectedPost.postImage)
  7. if let index = dataStore.albums.firstIndex(of: removeFromFavorite) {
  8. dataStore.albums.remove(at: index)
  9. }
  10. } else {
  11. // This line is new
  12. selectedPost.isLiked = true
  13. let addToFavorite = Album(title: selectedPost.title, author: selectedPost.author, postImage: selectedPost.postImage)
  14. dataStore.albums.append(addToFavorite)
  15. }
  16. }

答案2

得分: -1

  1. class DataStore: ObservableObject {
  2. var posts = [
  3. Post(postImage: "post1", title: "Black Widow", description: "some description", starRating: 4, numberOfRatings: 251, postRating: 7.1, postDuration: 134, postLanguage: "English", publishedBy: "Alina", publishedYear: 2001, isLiked: false, author: "someAuthor1")
  4. ]
  5. func togglePostLike(post: Post) {
  6. if let index = posts.firstIndex(where: { $0.id == post.id }) {
  7. posts[index].isLiked.toggle()
  8. objectWillChange.send() // refresh ui
  9. }
  10. }
  11. }
  12. Next add onReceive SwiftUIView
  13. .onReceive(dataStore.objectWillChange) { _ in
  14. // update State here
  15. }
英文:
  1. class DataStore: ObservableObject {
  2. var posts = [
  3. Post(postImage: "post1", title: "Black Widow", description: "some description", starRating: 4, numberOfRatings: 251, postRating: 7.1, postDuration: 134, postLanguage: "English", publishedBy: "Alina", publishedYear: 2001, isLiked: false, author: "someAuthor1")
  4. ]
  5. func togglePostLike(post: Post) {
  6. if let index = posts.firstIndex(where: { $0.id == post.id }) {
  7. posts[index].isLiked.toggle()
  8. objectWillChange.send() // refresh ui
  9. }
  10. }
  11. }

Next add onReceive SwiftUIView

  1. .onReceive(dataStore.objectWillChange) { _ in
  2. // update State here
  3. }

huangapple
  • 本文由 发表于 2023年5月25日 14:51:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76329588.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定