Как вызвать table.reloadData с помощью didReceiveData() в сеансе с использованием многорангового подключения (Swift 3)

Я борюсь с проблемой, заключающейся в том, что когда я получаю данные из сеанса с использованием инфраструктуры многорангового подключения, я хочу обновить данные и мгновенно перезагрузить таблицу контроллера представления.

Вот мои коды для функции didReceiveData 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)

    }
}

Для функции синхронизации в 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 при получении данных. Однако когда дело доходит до appDelegate.resultViewController.tableView.reloadData(), консоль выдает fatal error: unexpectedly found nil while unwrapping an Optional value. Я потратил весь день на то, чтобы понять, почему tableView равен нулю, но до сих пор не придумал.

Может кто-нибудь помочь плз. Спасибо

Я попробовал следующие коды, предоставленные @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() } в контроллере представления результатов. Кроме того, NotificationCenter.default.post(name: NSNotification.Name(rawValue: "syncWinner"), object: nil) в WinnerDataController.

В консоли печатается "testing". Однако через несколько секунд отображается сообщение «Это приложение модифицирует механизм автомакета из фонового потока после того, как доступ к механизму был получен из основного потока. Это может привести к повреждению механизма и странным сбоям».

Затем я попробовал это:

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

}

Теперь ошибка не отображается. Но таблица еще не перезагружена...


person lulusen    schedule 07.12.2017    source источник


Ответы (2)


В resultViewController вы можете настроить наблюдателя уведомлений для перезагрузки таблицы.

вы можете установить таким образом

// Регистрация и добавление наблюдателя в контроллер представления результатов

 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 
 }

И когда вы закончите получать данные, вы можете опубликовать уведомление, подобное этому

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

Таким образом, это опубликует уведомление, которое вы установили в контроллере представления результатов, а затем ваша задача будет выполнена.

Примечание. Это всего лишь псевдокод, поэтому он может содержать ошибку.

Если ваше приложение вносит изменения в пользовательский интерфейс, когда вы вносите изменения в пользовательский интерфейс при выполнении этой задачи, И я думаю, вам также потребуется снова получить данные из базы данных перед перезагрузкой табличного представления, потому что в соответствии с вашим кодом, который вы предоставили в вопросе вы напрямую перезагружаете таблицу. Вы можете проверить текущий поток следующим образом,

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

Надеюсь это поможет

person Hitesh Sultaniya    schedule 07.12.2017

С помощью @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, он не является основным потоком и не имеет самого обновленного списка победителей. На самом деле таблица была перезагружена с устаревшим списком победителей. Поэтому кажется, что таблица еще не перезагружена.

Затем я добавил self.updateList(), чтобы этот поток мог получать самые последние данные ядра. Наконец, это работает.

Надеюсь, это будет полезно для тех, кто борется с той же проблемой, что и я.

person lulusen    schedule 08.12.2017