iOS 在显示新视图之前 segue 冻结多秒
iOS segue freeze for many seconds before showing new view
在我的应用程序的主视图中,我有一个 table 视图和两个原型单元格。我已经使用故事板为每个单元格配置了转场。在视图控制器中,我重写了 prepareForSegue 以将有关所选单元格的信息传递到目标视图。
目标视图不是特别复杂,当然不需要任何繁重的处理来加载。
问题
当我第一次点击主控制器中的单元格时,目标视图会在 5 到 40 秒的长时间延迟后出现。
编辑 #2:后续点击通常更快
注意:
- 如果我在目标视图出现之前再次点击同一个单元格,这会触发目标视图立即出现。
- 同上,但点击不同的单元格会立即显示视图,但会显示第一个单元格中的数据。
- 同上,但点击不同的控件(没有关联的 segues)会触发目标视图立即出现。
- 随后的 "taps" 通常表现出较少的延迟。
- Time Profiler - 据我所见 - 显示在那么多秒的延迟期间绝对没有发生任何事情。
- 我尝试过不同类型的转场,但没有任何区别
一些 println 显示发生了以下事件序列:
- 在主视图中,执行 prepareForSegue(无延迟)
- 然后执行目标 viewDidLoad(无延迟)
- ...长时间延迟...
- 目标控制器中的集合和 table 视图开始调用数据源相关方法以从控制器获取数据。
- 视图终于出现了(顺便说一句,有一个不需要的动画,但那是另一个问题)
根据我对这个主题的阅读,我怀疑这个问题可能与后台线程中发生的上述某些操作有关。
知道我做错了什么吗?
编辑#1:添加了一些代码
在主视图控制器中,segues link 使用故事板(CTRL-将两个原型单元格拖到目标视图中)。
代码如下所示:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
var assetIndex = assetsTable.indexPathForSelectedRow()?.row
println("prepare for segue - start: \(assets[assetIds[assetIndex!]]!.Name)")
if let destination = segue.destinationViewController as? AssetThingsListViewController
{
destination.bundlesRepository = bundlesRepository!
destination.asset = assets[assetIds[assetIndex!]]
}
println("prepare for segue - end")
}
编辑 #3 我已经在 BitBucket
上提供了一个示例项目
很难说,除非您 post 您的代码响应单元格上的点击并呈现新的视图控制器。
UI 更改(或 UI 更改从未发生)长时间延迟的一个常见原因是试图从后台线程进行 UI 更改。您调用 segue 的代码是否可能在不同的线程上 运行?您可以通过在该代码上设置断点并观察中断时的线程号来轻松判断这一点。如果线程号为 0,则您在主线程上 运行。如果是其他线程号,那是你的问题。
我检查了你的项目。虽然我也找不到其他任何东西,但我也怀疑这是线程问题。
我设法通过为 tableview
实现委托并在代码中呈现新控制器来解决问题:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let destination = storyboard?.instantiateViewControllerWithIdentifier("BuilderToysListViewController") as! BuilderToysListViewController
destination.botsRepository = botsRepository!
destination.builder = builders[builderIds[indexPath.row]]
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.presentViewController(destination, animated: true) { () -> Void in
}
})
}
请注意,您已设置视图控制器故事板 ID:BuilderToysListViewController
并且还设置了表视图委托。不要忘记删除 segues。
最后在新视图控制器中关闭视图使用此代码:
@IBAction func backButton(sender: AnyObject)
{
dismissViewControllerAnimated(true, completion: { () -> Void in
})
// performSegueWithIdentifier("segueToysByBuilder", sender: nil)
}
这将使您能够正确关闭视图,而不是错误地创建一个新视图。
同样值得将代码从 viewWillAppear 移动到 viewDidAppear
我能够通过实施以下内容解决 iOS 13 和 Swift 5 的问题:
DispatchQueue.main.async {
self.performSegue(withIdentifier: "YOURSEGUEID", sender: nil)
}
在
里面
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {}
最终结果
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
DispatchQueue.main.async {
self.performSegue(withIdentifier: "YOURSEGUEID", sender: nil)
}
}
在我的应用程序的主视图中,我有一个 table 视图和两个原型单元格。我已经使用故事板为每个单元格配置了转场。在视图控制器中,我重写了 prepareForSegue 以将有关所选单元格的信息传递到目标视图。
目标视图不是特别复杂,当然不需要任何繁重的处理来加载。
问题
当我第一次点击主控制器中的单元格时,目标视图会在 5 到 40 秒的长时间延迟后出现。
编辑 #2:后续点击通常更快
注意:
- 如果我在目标视图出现之前再次点击同一个单元格,这会触发目标视图立即出现。
- 同上,但点击不同的单元格会立即显示视图,但会显示第一个单元格中的数据。
- 同上,但点击不同的控件(没有关联的 segues)会触发目标视图立即出现。
- 随后的 "taps" 通常表现出较少的延迟。
- Time Profiler - 据我所见 - 显示在那么多秒的延迟期间绝对没有发生任何事情。
- 我尝试过不同类型的转场,但没有任何区别
一些 println 显示发生了以下事件序列:
- 在主视图中,执行 prepareForSegue(无延迟)
- 然后执行目标 viewDidLoad(无延迟)
- ...长时间延迟...
- 目标控制器中的集合和 table 视图开始调用数据源相关方法以从控制器获取数据。
- 视图终于出现了(顺便说一句,有一个不需要的动画,但那是另一个问题)
根据我对这个主题的阅读,我怀疑这个问题可能与后台线程中发生的上述某些操作有关。
知道我做错了什么吗?
编辑#1:添加了一些代码
在主视图控制器中,segues link 使用故事板(CTRL-将两个原型单元格拖到目标视图中)。
代码如下所示:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
var assetIndex = assetsTable.indexPathForSelectedRow()?.row
println("prepare for segue - start: \(assets[assetIds[assetIndex!]]!.Name)")
if let destination = segue.destinationViewController as? AssetThingsListViewController
{
destination.bundlesRepository = bundlesRepository!
destination.asset = assets[assetIds[assetIndex!]]
}
println("prepare for segue - end")
}
编辑 #3 我已经在 BitBucket
上提供了一个示例项目很难说,除非您 post 您的代码响应单元格上的点击并呈现新的视图控制器。
UI 更改(或 UI 更改从未发生)长时间延迟的一个常见原因是试图从后台线程进行 UI 更改。您调用 segue 的代码是否可能在不同的线程上 运行?您可以通过在该代码上设置断点并观察中断时的线程号来轻松判断这一点。如果线程号为 0,则您在主线程上 运行。如果是其他线程号,那是你的问题。
我检查了你的项目。虽然我也找不到其他任何东西,但我也怀疑这是线程问题。
我设法通过为 tableview
实现委托并在代码中呈现新控制器来解决问题:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let destination = storyboard?.instantiateViewControllerWithIdentifier("BuilderToysListViewController") as! BuilderToysListViewController
destination.botsRepository = botsRepository!
destination.builder = builders[builderIds[indexPath.row]]
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.presentViewController(destination, animated: true) { () -> Void in
}
})
}
请注意,您已设置视图控制器故事板 ID:BuilderToysListViewController
并且还设置了表视图委托。不要忘记删除 segues。
最后在新视图控制器中关闭视图使用此代码:
@IBAction func backButton(sender: AnyObject)
{
dismissViewControllerAnimated(true, completion: { () -> Void in
})
// performSegueWithIdentifier("segueToysByBuilder", sender: nil)
}
这将使您能够正确关闭视图,而不是错误地创建一个新视图。
同样值得将代码从 viewWillAppear 移动到 viewDidAppear
我能够通过实施以下内容解决 iOS 13 和 Swift 5 的问题:
DispatchQueue.main.async {
self.performSegue(withIdentifier: "YOURSEGUEID", sender: nil)
}
在
里面func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {}
最终结果
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
DispatchQueue.main.async {
self.performSegue(withIdentifier: "YOURSEGUEID", sender: nil)
}
}