如何使用 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()
让这个线程得到最新的核心数据。最后,它起作用了。
希望这对那些和我有同样问题的人有所帮助。
我正在努力解决一个问题,当我使用 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()
让这个线程得到最新的核心数据。最后,它起作用了。
希望这对那些和我有同样问题的人有所帮助。