如何使用 Multipeer Connectivity 在会话中通过 didReceiveData() 调用 table.reloadData (Swift 3)

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

我正在努力解决一个问题,当我使用 Multipeer Connectivity 框架从会话接收数据时,我想更新数据并立即重新加载视图控制器的 table。

这是我的 MPCHandler 的 didReceiveData 函数的代码:

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)

    }
}

对于 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()
}

我想在收到数据后更新并重新加载 resultViewContoller 的 table。然而,当它到达 appDelegate.resultViewController.tableView.reloadData() 时,控制台给出 fatal error: unexpectedly found nil while unwrapping an Optional value。我花了一整天的时间来弄清楚为什么 tableView 是 nil,但仍然没有任何想法。

有人可以帮忙吗。谢谢

我尝试了@Hitesh Sultaniya 提供的以下代码:结果视图控制器中的NotificationCenter.default.addObserver(self, selector: #selector(testing), name: NSNotification.Name(rawValue: "syncWinner"), object: nil)func testing(notification: Notification){ print("testing") self.tableView.reloadData() }。此外,WinnerDataController 中的 NotificationCenter.default.post(name: NSNotification.Name(rawValue: "syncWinner"), object: nil)

在控制台中,打印出"testing"。然而,几秒钟后, "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" 显示。

然后,我尝试了这个:

func testing(notification: Notification){
DispatchQueue.global(qos: .userInitiated).async{
   self.tableView.reloadData()
}

}

现在,没有显示任何错误。但是 table 还没有重新加载...

在 resultViewController 中你可以设置 Notification observer 来重新加载 tableview

可以这样设置

// 在结果视图控制器中注册并添加观察者

 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 
 }

当您完成接收数据后,您可以post这样的通知

NSNotificationCenter.defaultCenter().postNotificationName(notificationName, object: nil)

所以这将 post 通知您在结果视图控制器中设置,然后您的任务将被执行

注意:这只是伪代码,因此可能包含错误

如果您的应用程序进行 UI 更改,那么您在执行此任务时进行 UI 更改的位置 而且我认为您还需要在重新加载 table 视图之前再次从数据库中获取数据,因为根据您提供的相关代码,您直接重新加载 table . 您可以像这样检查当前线程,

 if (Thread.isMainThread == true)
 {
                    //Perform UI Task 
 }
 else
 {
      //Dispatch for main queue with synchronous not asynchronous and then update the UI
 }

希望对您有所帮助

在@Hitesh Sultaniya 的帮助下,我解决了这个问题。

这是我的有效代码:

对于 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()
    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "syncWinner"), object: nil)

对于 ResultViewController:

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(testing), name: NSNotification.Name(rawValue: "syncWinner"), object: nil)
    appDelegate = UIApplication.shared.delegate as! AppDelegate
    }

func testing(notification: Notification){
    if Thread.isMainThread == true{
        self.tableView.reloadData()
        print("main thread")
    }
    else{
        DispatchQueue.main.sync {
            self.updateList()
            print(winnerList.count)
            self.tableView.reloadData()
            print("not main thread")

        }
    }

最初,我在 ResultViewController 中尝试过这个但不起作用

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(testing), name: NSNotification.Name(rawValue: "syncWinner"), object: nil)
    appDelegate = UIApplication.shared.delegate as! AppDelegate
    }

func testing(notification: Notification){
    if Thread.isMainThread == true{
        self.tableView.reloadData()
        print("main thread")
    }
    else{
        DispatchQueue.main.sync {
            self.tableView.reloadData()
            print("not main thread")

        }
    }

因为它在运行DispatchQueue.main.sync的block时,不是主线程,还没有拿到最新的winnerList。事实上,table 已经用过时的 winnerList 重新加载了。因此,似乎 table 尚未重新加载。

然后,我加了self.updateList()让这个线程得到最新的核心数据。最后,它起作用了。

希望这对那些和我有同样问题的人有所帮助。