TableView relsoaddata from textField on the same viewController with TableView

I have a viewController that has tableview that is updated from Parse Server. My query and reload data function is under

override func viewDidAppear( animated: Bool) {

        super.viewDidAppear(animated)

        loadData() // this is my function that queries and reloads data

    }

I have also a textField from which a message is captured updates the database and calls loadData() as follows:

@IBAction func composeButton(
sender: Any) {

        //inputAlert()

        

        if (feedInputField.text != "" ) {

        let reqType = Int(reqTypeIndex.text ?? "") ?? 0

         AddFeedbacks(message: feedInputField.text ?? "", taskId: idTask?.text ?? "", atype: reqType)

         loadData()

        feedInputField.text = ""

        }

    }


Problem : When the app first loads, it loads existing messages in the database.
And if I add a new message from the feedInputField, the tableView is not updated but if I added a second message, it then displays both messages. From there, it starts updating normaly. The issue is only when i load the app and after that it works.

My question what is the issue?

what is the issue?

Not enough info in your post.
How is loadData() implemented? Does it handle multi-threading and/or asynchronous calls properly?
The following is the function that loadData()

//**********************************
func r_feedback(rtaskId: String) {

        var singleFeed = myFeedback()

         self.arrayOfFeedback.removeAll()

        

        queryFeedback(taskId: rtaskId).findObjectsInBackground { (objects, error) in

            if let objects = objects {

                

                if (objects.count > 0) {

                for eachFeed in objects {

                    singleFeed.feedDate = eachFeed.createdAt!

                    singleFeed.userNameFrom = eachFeed["UserNameFrom"] as? String

                    singleFeed.feedMessage = eachFeed["TaskFeedback"] as? String

                    singleFeed.atype = eachFeed["AType"] as? Int

                    self.arrayOfFeedback.append(singleFeed)

                   

                }

              } else {

                

                singleFeed.feedDate = nil

                singleFeed.userNameFrom = ""

                singleFeed.feedMessage = ""

                singleFeed.atype = nil 

               

           }

          

            self.fTableView.reloadData() 

          

            }

        }

    }
//
**********************************

In turn funcion r_feedback(rtaskId: String) calls function queryFeedback() that fetches data in background and appends my array arrayOfFeedback and at the end calls TableView.reloadData(). I am using Parse Server as backend.
I just want to clarifies that if I use an additional viewController with textField to add messages, because this other viewController is called on top of the viewController that displays all the messages, it works but because I do not prefer to go have additional viewController but instead use the same viewController to update the messages, that's when I have this behavior
Please better format the code you post:

override func viewDidAppear( animated: Bool) {
Code Block
super.viewDidAppear(animated)

loadData() // this is my function that queries and reloads data
Code Block
}

I have also a textField from which a message is captured updates the database and calls loadData() as follows:

Code Block
@IBAction func composeButton( sender: Any) {
//inputAlert()
if (feedInputField.text != "" ) {
let reqType = Int(reqTypeIndex.text ?? "") ?? 0
AddFeedbacks(message: feedInputField.text ?? "", taskId: idTask?.text ?? "", atype: reqType)
loadData()
feedInputField.text = ""
}
}



Code Block
func r_feedback(rtaskId: String) {
var singleFeed = myFeedback()
self.arrayOfFeedback.removeAll()
queryFeedback(taskId: rtaskId).findObjectsInBackground { (objects, error) in
if let objects = objects {
if (objects.count > 0) {
for eachFeed in objects {
singleFeed.feedDate = eachFeed.createdAt!
singleFeed.userNameFrom = eachFeed["UserNameFrom"] as? String
singleFeed.feedMessage = eachFeed["TaskFeedback"] as? String
singleFeed.atype = eachFeed["AType"] as? Int
self.arrayOfFeedback.append(singleFeed)
}
} else {
singleFeed.feedDate = nil
singleFeed.userNameFrom = ""
singleFeed.feedMessage = ""
singleFeed.atype = nil
}
self.fTableView.reloadData()
}
}
}


What is AddFeedbacks ?
Note: name should start with lowerCase.

Problem : When the app first loads, it loads existing messages in the database.
And if I add a new message from the feedInputField, the tableView is not updated but if I added a second message, it then displays both messages. From there, it starts updating normaly. The issue is only when i load the app and after that it works.

Problem could be that addFeedbacks executes in another thread asynchronously. And completes after you reload.




func addFeedbacks(message: String,taskId: String,atype: Int) {
    if currentUser != nil {
    let feed = PFObject(className: "Feedback")
    feed["TaskId"] = taskId
    feed["TaskFeedback"] = message
    feed["UserNameFrom"] = currentUser?.username!
    feed["AType"] = atype
  feed.saveInBackground()
    }
}

I am sorry I am new to the forum and I am still struggling to format my text.
I think Claude31 is right but I need help to make it work. "feed.saveInBackgound()" does the job after because I have made a test by inserting print(arrayFeedback) between "addFeedbacks" and "loadData()" and the result is that there is a delay which means reloadData() is called before "arrayFeedback" is updated.
You're new here, normal you have a few things to learn.

To format, just select the code section and apply the <> tool:
Code Block
func addFeedbacks(message: String,taskId: String,atype: Int) {
if currentUser != nil {
let feed = PFObject(className: "Feedback")
feed["TaskId"] = taskId
feed["TaskFeedback"] = message
feed["UserNameFrom"] = currentUser?.username!
feed["AType"] = atype
feed.saveInBackground()
}
}


Please show saveInBackground()

Maybe you could call reload() inside saveInBackground(), but I need to see what the func is to confirm.
saveInBackground() is a Parse Server function that saves data to mongoDB.
However I have tried to include self.fTableView.reloadData() of my r_feedback() function into DispatchQueue.main.async and it seems to work but I am still testing:



  DispatchQueue.main.async {
                    self.fTableView.reloadData()
                }
Is queryFeedback() your function or from a framework.
If you have code, could you show ?
Code Block
func queryFeedback(taskId: String) -> PFQuery<PFObject> {
let query = PFQuery(className:"Feedback")
query.whereKey("TaskId", equalTo: taskId)
query.order(byAscending: "CreatedAt")
return query
}

queryFeedback() is my function just to simplify my code by returning a PFOBject that is a snapshot of my query.
This PFOBject is then carried in background into my r_feedback() function.
Thanks for your help, my format works now

my format works now

Do you mean no more problem ?

If so, congrats. Don't forget to close the thread.

Just for my own knowledge, which framework is PFQuery coming from ? The Parse Server ?
No, I am still having the same issue.
It happens only when I load the application. The first time I post a message to be added, reloadData() is delayed until a second message is posted. From there once the app is in memory, it works normally.
It would be necessary to see the complete class code.
Because you probably reload() before data are updated (due to some async call).
But impossible to spot exactly where without getting the complete code.

Please show also the loadData() func itself, as it was asked some time ago.
As you call in viewDidAppear, may be table is displayed before the loading is complete.
Do you call reloadData() for the tableView at the end of loadData() ?

From there once the app is in memory, it works normally.

Do you mean you may call the reload before the end of app loading ???
Code Block
 override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(true)
        loadData()
    }


Code Block
func loadData() {
        r_feedback(rtaskId: idTask.text ?? "")
        buttonChange()
    }


Code Block
func r_feedback(rtaskId: String) {
        var singleFeed = myFeedback()
         self.arrayOfFeedback.removeAll()
        queryFeedback(taskId: rtaskId).findObjectsInBackground { (objects, error) in
            if let objects = objects { 
                if (objects.count > 0) {
                for eachFeed in objects {
                    singleFeed.feedDate = eachFeed.createdAt!
                    singleFeed.userNameFrom = eachFeed["UserNameFrom"] as? String
                    singleFeed.feedMessage = eachFeed["TaskFeedback"] as? String
                    singleFeed.atype = eachFeed["AType"] as? Int
                    self.arrayOfFeedback.append(singleFeed)
                }
              } else {
                singleFeed.feedDate = nil
                singleFeed.userNameFrom = ""
                singleFeed.feedMessage = ""
                singleFeed.atype = nil 
           }
                DispatchQueue.main.async {
                    self.fTableView.reloadData()
                }
            }
        }
    }


Code Block
func queryTasks(field: String) -> PFQuery<PFObject> {
let query = PFQuery(className:"Tasks")
query.whereKey(field, equalTo: (currentUser?.username)!)
query.order(byAscending: "TaskDeadline")
return query
}


I have posted the complete code. This code reloads the viewcontroller without issue if I place the update textfield on another viewcontroller that is called on top of the one displaying the feedback because the Back button will call viewDidAppear() function. But I prefer having update textfield on the same viewcontroller the way the chat message works.
Your help is appreciated.
That's not the complete code.

For instance, do not see where is buttonChange() defined.
buttonChange() was let out because it is included only to keep my codes clean. It does change the status on a button and has got nothing to do with the viewController. I can even leave it out. It is not related. However composeButton() does because the codes call loadata() after inserting a new message and I guess this one is related.

Code Block
func buttonChange() {
        let stat = taskStatus?.text
        let rqType = Int(reqTypeIndex.text ?? "") ?? 0
        switch(rqType) {
        case 0:
            if (stat == status[1]) || (stat == status[3]) {
                statusChange(imageLabel: task_image[2])
            } else {
                statusChange(imageLabel: "")
            }
        case 1:
            if (stat == status[2]) {
                statusChange(imageLabel: task_image[3])
            } else {
                statusChange(imageLabel: "")
            }
        default:
            statusChange(imageLabel: "")
        }
    }


Code Block
@IBAction func composeButton(_ sender: Any) {
        if (feedInputField.text != "" ) {
        let reqType = Int(reqTypeIndex.text ?? "") ?? 0
        AddFeedbacks(message: feedInputField.text ?? "", taskId: idTask?.text ?? "", atype: reqType)
        loadData()
        feedInputField.text = ""
        }
    }


Code Block
func AddFeedbacks(message: String,taskId: String,atype: Int) {
    if currentUser != nil {
    let feed = PFObject(className: "Feedback")
    feed["TaskId"] = taskId
    feed["TaskFeedback"] = message
    feed["UserNameFrom"] = currentUser?.username!
    feed["AType"] = atype
    feed.saveInBackground()
    }
}


PFObject() is a framework class
feedInputField and composeButton are on the toolbar.

Thanks for your help
I would thus investigate the sequence of events (by just adding some prints to start with.
Possibly, when loadData() is called, data are not yet loaded…

Code Block
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
print(#function, "going to loadData") // <<<<====
loadData()
}
func loadData() {
r_feedback(rtaskId: idTask.text ?? "")
print(#function, "going to buttonChange") // <<<<====
buttonChange()
}
func r_feedback(rtaskId: String) {
var singleFeed = myFeedback()
self.arrayOfFeedback.removeAll()
queryFeedback(taskId: rtaskId).findObjectsInBackground { (objects, error) in
if let objects = objects {
if (objects.count > 0) {
print(#function, "queryFeedback") // <<<<====
for eachFeed in objects {
singleFeed.feedDate = eachFeed.createdAt!
singleFeed.userNameFrom = eachFeed["UserNameFrom"] as? String
singleFeed.feedMessage = eachFeed["TaskFeedback"] as? String
singleFeed.atype = eachFeed["AType"] as? Int
self.arrayOfFeedback.append(singleFeed)
}
} else {
singleFeed.feedDate = nil
singleFeed.userNameFrom = ""
singleFeed.feedMessage = ""
singleFeed.atype = nil
}
DispatchQueue.main.async {
print(#function, "going to reloadData") // <<<<====
self.fTableView.reloadData()
}
}
}
}
func buttonChange() {
let stat = taskStatus?.text
let rqType = Int(reqTypeIndex.text ?? "") ?? 0
switch(rqType) {
case 0:
if (stat == status[1]) || (stat == status[3]) {
statusChange(imageLabel: task_image[2])
} else {
statusChange(imageLabel: "")
}
case 1:
if (stat == status[2]) {
statusChange(imageLabel: task_image[3])
} else {
statusChange(imageLabel: "")
}
default:
statusChange(imageLabel: "")
}
print(#function, "button has changed") // <<<<====
}

Please show the complete log.
TableView relsoaddata from textField on the same viewController with TableView
 
 
Q