Search code examples
iosswiftswift3multipeer-connectivity

How to call table.reloadData by didReceiveData() in session using Multipeer Connectivity (Swift 3)


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...


Solution

  • 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