[编辑]:我想我已经解决了锁定问题。在将退出准备工作重构didSelectRowAt
为 ping 异步队列中的阻塞任务时,我注意到成功的转换将包括一次瞬时移动到 rootVC,然后再次动画转换到 rootVC。让我意识到我的 tableVC 有两个 segue:一个是控制器 segue 的通用控制器(这是预期的 segue 方法),另一个是选择表格单元格。
我不确定是否只是删除了额外的 segue 或多个尝试的解决方案的组合以及解决了问题的 segue 的删除。我的猜测是后者,因为记忆告诉我,曾经有一段时间只有一个 segue 并且“修复”也不起作用。
tl;dr:确保你没有竞争的 segues 并且你的异步代码是线程安全的/有适当的清理。
[问题]:
我有一个 TableViewController,它是导航控制器下 rootVC 的子 VC。换句话说,NavController[rootVC, tableVC]。
该应用程序在 rootVC 中启动,并通过 UIButton 连接到 tableVC。在 tableVC 的 viewDidLoad 处,如果之前没有完成之前的扫描,则完成网络扫描。网络上的设备在被发现时会在某个端口异步 ping。如果这些 ping 成功,则与设备关联的 IP 地址用于填充表格视图中的单元格。如果选择了此单元格,则会通过 didSelectRowAt indexPath 更改某些应用程序设置,并执行展开转场以返回到 rootVC。viewWillDisappear 也用于通过 isMovingFromParentViewController 传递值(之前通过准备 segue 完成,但也存在错误)。用户可以在 IP 地址单元格出现在表视图中时立即选择它,这是预期的设计。
该功能一切正常。大多数时候。但是,在未完成扫描的情况下选择了一个单元格后,应用程序有时会在选择一个单元格后锁定(这意味着仍然可能有异步 ping 发生/排队)。我在 didSelectAtRow 的开头有一个打印,当锁定发生时永远不会发生。我在表格视图中还有一个活动指示器视图,当其他一切都没有响应时,它会继续旋转。Xcode 方面没有崩溃或中断。似乎 didSelectAtRow 只是没有发生并且由于某种原因无法继续。
这就是我的 didSelectAtRow 的样子
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Cell was selected")
if possibleDevices.count != 0 {
selectedTableCellAddress = possibleDevices[indexPath.row]
let defaults = UserDefaults.standard
// Set the current cell's IP Address to the setting's IP Address
if selectedTableCellAddress != nil {
pingOperationsShouldStop = true
lanScanner.stop()
defaults.set(selectedTableCellAddress, forKey: "address")
}
}
}
注意 lanScanner 是 MMLanScan 的一个实例
我的新手知识让我猜测这是由于我的异步 ping(ping 结果是控制台上显示的最后内容)。当在 LAN 上找到设备时,会发生异步功能。它被封装在这样的函数中:
DispatchQueue.global(qos: .userInteractive).async {
print("pingOperationsShouldStop? \(self.pingOperationsShouldStop)")
if self.pingOperationsShouldStop {
print("Skipping ping for \(addr)")
return
}
self.pingOperationsHaveStopped = false
let port = Int32(self.portStr)
let client = TCPClient(address: address, port: port!)
switch client.connect(timeout: 1) {
case .success:
print("connected")
DispatchQueue.main.sync {
self.possibleDevices.append(address)
self.numberOfPossibleDevicesCounted += 1
self.pingOperations.leave()
}
client.close()
case .failure(let error):
print("failed due to \(error) for \(addr)")
DispatchQueue.main.sync {
self.numberOfPossibleDevicesCounted += 1
client.close()
self.pingOperations.leave()
}
}
}
注意 possibleDevices 有一个调用 reloadData 的 didSet 属性观察器。
起初我认为它只发生在单元格选择中(即 NavCon's Back 工作正常)。所以我以编程方式调用视图的弹出,但无济于事。我尝试通过 NavCon 的后退按钮重现锁定,并且能够做到一次。
我不确定哪些代码与共享相关,所以如果您需要更多信息,请告诉我。
谢谢!