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

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

SwiftUI: UI does not update on @Published var change

问题

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

模型:

struct Post: Identifiable{
    var id = UUID().uuidString
    var postImage: String
    var title: String
    var description: String
    var starRating: Int
    var numberOfRatings : Int
    var postRating : Double
    var postDuration : Int
    var postLanguage : String
    var publishedBy : String
    var publishedYear : Int
    var isLiked : Bool
    var author : String
}

class DataStore: ObservableObject {
    @Published var posts = [
        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"),
    ]
    
    func togglePostLike(post: Post) {
        if let index = posts.firstIndex(where: { $0.id == post.id }) {
            posts[index].isLiked.toggle()
        }
    }
}

视图:

struct play: View {
    @State var selectedPost : Post?
    @EnvironmentObject private var dataStore : DataStore
    
    @State var switchView = false
    
    var body: some View {
        if switchView == false {
            // 在迭代中,我称每个元素为 "post"
            Image(systemName: post.isLiked ? "heart.fill" : "heart")
                .font(.system(size: 30))
                .foregroundColor(.red)
                .offset(x: 100, y: 150)
                .onTapGesture {
                    if post.isLiked == true {
                        dataStore.togglePostLike(post: post)
                        let removeFromFavorite = Album(title: post.title, author: post.author, postImage: post.postImage)
                        if let index = dataStore.albums.firstIndex(of: removeFromFavorite) {
                            dataStore.albums.remove(at: index)
                        }
                    } else {
                        dataStore.togglePostLike(post: post)
                        let addToFavorite = Album(title: post.title, author: post.author, postImage: post.postImage)
                        dataStore.albums.append(addToFavorite)
                    }
                }
            
            // 迭代所有的帖子,然后将 "selectedPost" 的值设置为点击的帖子
            ForEach(dataStore.posts, id:\.id) {post in
                Image("\(post.postImage)")
                    .onTapGesture {
                        selectedPost = post
                        switchView = true
                    }
            }
            
            switchView = true
        } else {
            NewView(selectedPost: selectedPost!)
                .environmentObject(dataStore)
        }
    }
}

struct NewView: View {
    @EnvironmentObject private var dataStore : DataStore
    
    var selectedPost : Post
    
    var body: some View {
        VStack {
            Text(String(selectedPost.isLiked))
            if selectedPost.isLiked {
                Circle()
                    .foregroundColor(.red)
                    .frame(width: 50, height: 50, alignment: .center)
                    .foregroundColor(.black)
                    .overlay(
                        Image(systemName: "heart")
                            .font(.system(size: 25))
                            .foregroundColor(.white)
                    )
                Text("Save")
            } else {
                Circle()
                    .strokeBorder(.black, lineWidth: 2.5)
                    .frame(width: 50, height: 50, alignment: .center)
                    .foregroundColor(.black)
                    .overlay(
                        Image(systemName: "heart")
                            .font(.system(size: 25))
                            .foregroundColor(.black)
                    )
                Text("Save")
            }
        }
        .onTapGesture {
            dataStore.togglePostLike(post: selectedPost)
            if selectedPost.isLiked == true {
                let removeFromFavorite = Album(title: selectedPost.title, author: selectedPost.author, postImage: selectedPost.postImage)
                if let index = dataStore.albums.firstIndex(of: removeFromFavorite) {
                    dataStore.albums.remove(at: index)
                }
            } else {
                let addToFavorite = Album(title: selectedPost.title, author: selectedPost.author, postImage: selectedPost.postImage)
                dataStore.albums.append(addToFavorite)
            }
        }
    }
}

请注意,代码中可能存在一些 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:

struct Post: Identifiable{
var id = UUID().uuidString
var postImage: String
var title: String
var description: String
var starRating: Int
var numberOfRatings : Int
var postRating : Double
var postDuration : Int
var postLanguage : String
var publishedBy : String
var publishedYear : Int
var isLiked : Bool
var author : String
}
class DataStore: ObservableObject {
@Published var posts = [
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"),
]
func togglePostLike(post: Post) {
if let index = posts.firstIndex(where: { $0.id == post.id }) {
posts[index].isLiked.toggle()
}
}
}

View
UPDATED VIEW
UPDATED VIEW 2

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

 This update is to show how the two view work together. 
struct play: View {
@State var selectedPost : Post?
@EnvironmentObject private var dataStore : DataStore
@State var switchView = false
var body: some View {
if switchView == false {
// When iterating I call each element "post"
Image(systemName: post.isLiked ? "heart.fill" : "heart")
.font(.system(size: 30))
.foregroundColor(.red)
.offset(x: 100, y: 150)
.onTapGesture {
if post.isLiked == true {
dataStore.togglePostLike(post: post)
let removeFromFavorite = Album(title: post.title, author: post.author, postImage: post.postImage)
if let index = dataStore.albums.firstIndex(of: removeFromFavorite) {
dataStore.albums.remove(at: index)
}
} else {
dataStore.togglePostLike(post: post)
let addToFavorite = Album(title: post.title, author: post.author, postImage: post.postImage)
dataStore.albums.append(addToFavorite)
}
}
// Iterate all the posts and then give "selectedPost" the value of the clicked post
ForEach(dataStore.posts, id:\.id) {post in
Image("\(post.postImage)")
.onTapGesture {
selectedPost = post
switchView = true
}
}
switchView = true
} else {
NewView(selectedPost: selectedPost!)
.environmentObject(dataStore)
}
}
}
struct NewView: View {
@EnvironmentObject private var dataStore : DataStore
var selectedPost : Post
var body: some View {
VStack {
Text(String(selectedPost.isLiked))
if selectedPost.isLiked {
Circle()
.foregroundColor(.red)
.frame(width: 50, height: 50, alignment: .center)
.foregroundColor(.black)
.overlay(
Image(systemName: "heart")
.font(.system(size: 25))
.foregroundColor(.white)
)
Text("Save")
} else {
Circle()
.strokeBorder(.black, lineWidth: 2.5)
.frame(width: 50, height: 50, alignment: .center)
.foregroundColor(.black)
.overlay(
Image(systemName: "heart")
.font(.system(size: 25))
.foregroundColor(.black)
)
Text("Save")
}
}
.onTapGesture {
dataStore.togglePostLike(post: selectedPost)
if selectedPost.isLiked == true {
let removeFromFavorite = Album(title: selectedPost.title, author: selectedPost.author, postImage: selectedPost.postImage)
if let index = dataStore.albums.firstIndex(of: removeFromFavorite) {
dataStore.albums.remove(at: index)
}
} else {
let addToFavorite = Album(title: selectedPost.title, author: selectedPost.author, postImage: selectedPost.postImage)
dataStore.albums.append(addToFavorite)
}
}
}
}

答案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:

.onTapGesture {
dataStore.togglePostLike(post: selectedPost)
if selectedPost.isLiked == true {
// This line is new
selectedPost.isLiked = false
let removeFromFavorite = Album(title: selectedPost.title, author: selectedPost.author, postImage: selectedPost.postImage)
if let index = dataStore.albums.firstIndex(of: removeFromFavorite) {
dataStore.albums.remove(at: index)
}
} else {
// This line is new
selectedPost.isLiked = true
let addToFavorite = Album(title: selectedPost.title, author: selectedPost.author, postImage: selectedPost.postImage)
dataStore.albums.append(addToFavorite)
}
}

答案2

得分: -1

    class DataStore: ObservableObject {
     var posts = [
        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")
    ]

    func togglePostLike(post: Post) {
        if let index = posts.firstIndex(where: { $0.id == post.id }) {
            posts[index].isLiked.toggle()
            objectWillChange.send() // refresh ui
        }
    }
    }

Next add onReceive SwiftUIView

    .onReceive(dataStore.objectWillChange) { _ in 
       // update State here 
    }
英文:
class DataStore: ObservableObject {
var posts = [
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")
]
func togglePostLike(post: Post) {
if let index = posts.firstIndex(where: { $0.id == post.id }) {
posts[index].isLiked.toggle()
objectWillChange.send() // refresh ui
}
}
}

Next add onReceive SwiftUIView

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

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:

确定