英文:
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 编码(例如 "
)或未定义的变量(例如 post
和 Album
),你需要根据实际情况进行调整。
英文:
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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论