I am struggling on a problem that when I receive data from session using Multipeer Connectivity framework, I want to update the data and reload the table of a view controller instantly.
Here are my codes for didReceiveData function of MPCHandler:
func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
NSLog("%@", "didReceive: \(data)")
if var dict: [NSDictionary] = NSKeyedUnarchiver.unarchiveObject(with: data) as? [NSDictionary]{
let d = dict.removeFirst()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.winnerDataController.syncWinnerFromDictionary(d: dict)
}
}
For sync function in WinnerDataController
func syncWinnerFromDictionary(d: NSDictionary){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let entityDescription = NSEntityDescription.entity(forEntityName: "Winner", in: context)!
let winner: Winner = NSManagedObject(entity: entityDescription, insertInto: context) as! Winner
winner.setValue(d.value(forKey: "index"), forKey: "index")
winner.setValue(d.value(forKey: "dept"), forKey: "dept")
winner.setValue(d.value(forKey: "name"), forKey: "name")
save()
appDelegate.resultViewController.tableView.reloadData()
}
I want to update and reload the table of resultViewContoller upon the receive of the data. However, when it goes to appDelegate.resultViewController.tableView.reloadData()
, the console gives out fatal error: unexpectedly found nil while unwrapping an Optional value
. I spent all day on figuring why the tableView is nil, yet still haven't got any ideas.
Could someone plz help. Thx
I tried the following codes as provided by @Hitesh Sultaniya: NotificationCenter.default.addObserver(self, selector: #selector(testing), name: NSNotification.Name(rawValue: "syncWinner"), object: nil)
and func testing(notification: Notification){
print("testing")
self.tableView.reloadData()
}
in result view controller. Also, NotificationCenter.default.post(name: NSNotification.Name(rawValue: "syncWinner"), object: nil)
in WinnerDataController.
In the console, "testing" is printed. However, after a few seconds, "This application is modifying the autolayout engine from a background thread after the engine was accessed from the main thread. This can lead to engine corruption and weird crashes" is shown.
Then, I tried this:
func testing(notification: Notification){
DispatchQueue.global(qos: .userInitiated).async{
self.tableView.reloadData()
}
}
Now, no error is shown. But the table is still not yet reloaded...
In resultViewController you can set Notification observer to reload tableview
you can set in this manner
// Register and add observer in result view controller
NotificationCenter.default.addObserver(self, selector: #selector(self.reloadTableView(_:)), name: NSNotification.Name(rawValue: "<Your Notfication Name>"), object: nil)
// handle notification
func reloadTableView(_ notification: NSNotification) {
//relaod your table view
}
And when you are done with receiving data you can post notification like this
NSNotificationCenter.defaultCenter().postNotificationName(notificationName, object: nil)
So this will post notification that you have set in result view controller and then your task will be performed
Note : This is just pseudo code so might contain error
If you application making UI changes that where you make UI changes while performing this task And I think you will also need to fetch data from database again before reloading table view because as per your code that you have provided in question you directly reloading table. You can check for current thread like this,
if (Thread.isMainThread == true)
{
//Perform UI Task
}
else
{
//Dispatch for main queue with synchronous not asynchronous and then update the UI
}
Hope this helps