0

I'm building a SwiftUI app with CRUD functionality with a mysql db. The CRUD operations work fine and after the create, update, or delete function the read function is called to get the updated data from the db. When I run the app the read function seems to be called before the create, update of delete function if I look at the console output so I only see the mutation after running the app again. Any idea how to fix this?

This is my create code

struct NewPostView: View {
@EnvironmentObject var viewModel: ViewModel
@Binding var isPresented: Bool
@Binding var title: String
@Binding var post: String
@State var isAlert = false

var body: some View {
    NavigationView {
        ZStack {
            Color.gray.opacity(0.1).edgesIgnoringSafeArea(.all)
            VStack(alignment: .leading) {
                Text("Create new post")
                    .font(Font.system(size: 16, weight: .bold))
                
                TextField("Title", text: $title)
                    .padding()
                    .background(Color.white)
                    .cornerRadius(6)
                    .padding(.bottom)
                
                TextField("Write something...", text: $post)
                    .padding()
                    .background(Color.white)
                    .cornerRadius(6)
                    .padding(.bottom)
                
                Spacer()
                
            }.padding()
            .alert(isPresented: $isAlert, content: {
                let title = Text("No data")
                let message =  Text("Please fill your title and post")
                return Alert(title: title, message: message)
            })
        }
        .navigationBarTitle("New post", displayMode: .inline)
        .navigationBarItems(leading: leading, trailing: trailing)
    }
}
var leading: some View {
    Button(action: {
        isPresented.toggle()
    }, label: {
        Text("Cancel")
    })
}

var trailing: some View {
    Button(action: {
        if title != "" && post != "" {
            let parameters: [String: Any] = ["title": title, "post": post]
            print(parameters)
            viewModel.createPost(parameters: parameters)
            viewModel.fetchPosts()
            
            isPresented.toggle()
        } else {
            isAlert.toggle()
        }
    }, label: {
        Text("Post")
    })
}
}

ViewModel

class ViewModel: ObservableObject {
@Published var items = [PostModel]()
let prefixURL = "https://asreconnect.nl/CRM/php/app"

init() {
    fetchPosts()
}

//MARK: - retrieve data
func fetchPosts() {
    guard let url = URL(string: "\(prefixURL)/posts.php") else {
        print("Not found url")
        return
    }
    
    URLSession.shared.dataTask(with: url) { (data, res, error) in
        if error != nil {
            print(data!)
            print("error", error?.localizedDescription ?? "")
            return
        }
        
        do {
            if let data = data {
                print(data)
                let result = try JSONDecoder().decode(DataModel.self, from: data)
                DispatchQueue.main.async {
                    self.items = result.data
                    print(result)
                }
            } else {
                print("No data")
            }
            
        } catch let JsonError {
            print("fetch json error:", JsonError.localizedDescription)
            print(String(describing: JsonError))
        }
    }.resume()
}

//MARK: - create data
func createPost(parameters: [String: Any]) {
    guard let url = URL(string: "\(prefixURL)/create.php") else {
        print("Not found url")
        return
    }
    
    let data = try! JSONSerialization.data(withJSONObject: parameters)
    print(data)
    
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.httpBody = data
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    
    URLSession.shared.dataTask(with: request) { (data, res, error) in
        if error != nil {
            print("error", error?.localizedDescription ?? "")
            return
        }
        
        do {
            if let data = data {
                let result = try JSONDecoder().decode(DataModel.self, from: data)
                DispatchQueue.main.async {
                    print(result)
                }
            } else {
                print("No data")
            }
            
        } catch let JsonError {
            print("fetch json error:", JsonError.localizedDescription)
        }
    }.resume()
}
}
jnpdx
  • 45,847
  • 6
  • 64
  • 94
RoyBerner
  • 55
  • 1
  • 9
  • This is not enough code to recreate the issue. My suspicion is that there are asynchronous operations happening in `createPost` and `fetchPosts`, but you haven't included the relevant code to show whether this is the case. – jnpdx Jul 28 '21 at 19:50
  • I've updated my post with extra code. I hope this is enough for you to see what is going wrong. – RoyBerner Jul 28 '21 at 19:57
  • As I suspected, `createPost` and `fetchPosts` both have asynchronous URL calls. Have you searched for or read about "completion handlers" (also called "callback functions") in Swift? – jnpdx Jul 28 '21 at 20:01
  • Thanks for your input. I'm going to search how to fix this in SwiftUI! – RoyBerner Jul 28 '21 at 20:07
  • No problem. FYI, it's not specific to SwiftUI at all -- this is just a Swift issue. There are plenty of examples here on SO about how to fix this sort of thing. The first half of one of my other answers today (https://stackoverflow.com/a/68563499/560942) deals with callbacks, for example. – jnpdx Jul 28 '21 at 20:09

0 Answers0