Hello, I am creating a cooking recipe app at the moment and I want to implement the function to like a recipe. Every recipe is stored in a SQLite DB. If a post is liked or not decides a Boolean inside the DB which is called "isLiked". Usually it's false, but I created a button and when I click it, the bool value changes. Everything works fine but the moment I click the like button nothing is displayed in the view. I need to go to another view and then back. After it was re-rendered everything is displayed. How do I fix this error? I want to press the button and show it immediately. Thank you for any help!
Here's my Database class
class Database: ObservableObject {
var connection: OpaquePointer?
@Published var recipes = [Recipe]()
func connectDatabase() {
// the connection works
}
func getRecipes() -> [Recipe] {
var recipes = [Recipe]()
var statement: OpaquePointer?
let query = "SELECT * FROM recipes"
if sqlite3_prepare_v2(connection, query, -1, &statement, nil) != SQLITE_OK {
print("Error preparing select: \(query)")
} else {
while sqlite3_step(statement) == SQLITE_ROW {
// that code block is working too
recipes.append(recipe)
}
sqlite3_finalize(statement)
}
return recipes
}
// that's the function to toggle the isLiked value
func toggleData(id: Int) {
if let path = Bundle.main.path(forResource: "myRecipesDB", ofType: "db") {
if sqlite3_open(path, &connection) == SQLITE_OK
print("opening database was successful")
let selectSQL = "SELECT isLiked FROM recipes WHERE id = ?"
var selectStatement: OpaquePointer?
if sqlite3_prepare_v2(connection, selectSQL, -1, &selectStatement, nil) == SQLITE_OK {
sqlite3_bind_int(selectStatement, 1, Int32(id))
var currentIsLiked = false
if (sqlite3_step(selectStatement) == SQLITE_ROW) {
currentIsLiked = sqlite3_column_int(selectStatement, 0) == 1
} else {
print("Error while trying to get currentIsLiked status")
}
sqlite3_finalize(selectStatement)
let updateSQL = "UPDATE recipes SET isLiked = ? WHERE id = ?"
var updateStatement: OpaquePointer?
if sqlite3_prepare_v2(connection, updateSQL, -1, &updateStatement, nil) == SQLITE_OK {
sqlite3_bind_int(updateStatement, 1, !currentIsLiked ? 1 : 0)
sqlite3_bind_int(updateStatement, 2, Int32(id))
if sqlite3_step(updateStatement) != SQLITE_DONE {
print("Error while trying to update isLiked status")
} else {
self.recipes = self.getRecipes()
print("Recipe liked status updated")
objectWillChange.send()
}
sqlite3_finalize(updateStatement)
} else {
print("Error while trying to prepare the update statement")
}
} else {
print("Error while trying to prepare the select statement")
}
}
} else {
print("Error opening database")
}
}
}
The code below is a part of my view
struct conceptCell: View {
@ObservedObject var database = Database()
let recipe: Recipe
@State private var recipes = [Recipe]()
var body: some View {
Vstack {
Button(action: {
database.toggleData(id: recipe.id)
// that's the like button
}) {
Image(systemName: recipe.isLiked ? "heart.fill" : "heart")
.font(.system(size: 35))
.padding(7)
.background(.gray)
.cornerRadius(13)
}
}
}
}
The code below is the content view
struct ContentView: View {
@ObservedObject var database = Database()
@State private var recipes = [Recipe]()
let recipe: Recipe
var body: some View {
ScrollView(showsIndicators: false){
ForEach(recipes, id: \.id) {recipe in
conceptCell(recipe: recipe)
.padding(5)
.onAppear {
render()
}
}
}
}
func render() {
database.connectDatabase()
self.recipes = self.database.getRecipes()
}
}