【问题标题】:Unintended table reload/refresh with some delay意外的表重新加载/刷新有一些延迟
【发布时间】:2014-09-05 12:10:12
【问题描述】:

Xcode 6 - beta 6/7:我创建了一个带有概览(表格视图)和详细视图(网络视图)屏幕的 iOS 8 (Swift) 博客阅读器应用程序。如果有互联网连接,应用程序在启动时会从博客加载实际的 json 数据并将其作为实体对象保存到核心数据中。首先显示的表格视图然后用来自核心数据的那些对象填充其单元格。包含标题和副标题的单元格按预期完全加载。一切似乎都很好,但是......

  1. 如果我不交互而只是等待,表格视图会在大约 10 秒后快速刷新(单元格变为空白并在半秒内再次填充相同的文本)。之后一切正常,我可以单击命名的单元格并被转发到详细视图,我可以返回并选择其他任何一个。

  2. 如果我像往常一样立即开始交互,我必须单击单元格两次才能被转发到详细视图。很快回到概览时,我发现我的表格视图只填满了我刚刚点击的一个单元格,其余的都是空白。

  • 然后我可以再等待 5-15 秒,然后一切都会自动刷新(从那时起就可以正常工作了),或者
  • 我可以点击那些空白单元格然后立即再次可见,而 - 当然 - 我再次被转发到详细视图或
  • 如果我在详细视图上停留的时间更长,比如说阅读一些博客,然后返回,所有单元格都是可见的,因为同时有足够的时间进行这种奇怪的刷新

  • 注意:如果没有互联网连接,应用程序会成功从核心数据加载对象,但上述问题仍然存在。所以,无论如何,我必须等到“第二次刷新”发生后,才能像我想要的那样运行应用程序。

如果这是一个完全未知的问题,并且您必须查看一些代码以进行进一步调查,我很乐意分享。但是现在我还没有看到一点,因为它或多或少是使用表格视图时实现的基本代码。我对核心数据相当陌生,可能已经监督了一些事情,但到目前为止还没有注意到。 我会非常感谢您的帮助,因为我通常会在询问之前调查很长时间,但这次真的不知道原因可能是什么。

编辑:

补充一点可能很重要,我在 Xcode 中使用“主从应用程序”模板启动应用程序,并让我们使用它提供的方法来自动使用来自核心数据 (NSFetchedResultsController) 的正确实体对象填充单元格。代码的某些部分可能会提示进一步调查的位置(如果需要更多代码,请告诉我):

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
    self.configureCell(cell, atIndexPath: indexPath)
    return cell 
}    

func configureCell(cell: UITableViewCell, atIndexPath indexPath: NSIndexPath) {
    let object = self.fetchedResultsController.objectAtIndexPath(indexPath) as NSManagedObject
    cell.textLabel?.text = object.valueForKey("title")?.description
    let published = object.valueForKey("published")?.description
    let author = object.valueForKey("author")?.description
    let spaceholder = "   "
    cell.detailTextLabel?.text = published! + spaceholder + author!
}

编辑 2:

感谢输入 nzeltzer,我想我找到了重点:当代码的某些部分在全局(而不是主)线程上运行时,只是会出现上述问题。所以我做了一些测试:底部的控制台输出显示了应用程序第一次构建时的 NSThread.isMainThread() 结果。

当我第二次重新运行应用程序时,过程如下:核心数据已经有一些值,因此直接配置单元格(日志:_ is Main Thread)。然后,如果有互联网连接,它会删除(在 viewDidLoad 中)所有核心数据对象,再次加载 json 数据,将对象放入核心数据并再次创建单元格。日志的第二部分现在又是_ is NOT Main Thread。如果我现在在没有互联网连接的情况下运行该应用程序,则不会触发第二部分,而只会发生带有 _ is Main Thread 的第一个单元格配置。

对这种行为有什么直截了当的解释吗?

在任何情况下,调度那些可能导致主线程问题的部分的正确(优雅)方法是什么?是不是跟模板自带的 NSFetchedResultsController 有关系,还是有些任务自动分派到全局队列是正常的?

日志(应用构建第一次,10个单元格):

2014-09-08 13:04:54.821 Blog Reader[3682:193346] 17545849:_UIScreenEdgePanRecognizerEdgeSettings.edgeRegionSize=13.000000
2014-09-08 13:04:54.823 Blog Reader[3682:193346] 17545849:_UIScreenEdgePanRecognizerEdgeSettings.edgeRegionSize=13.000000
NumbersOfRowsInSection is Main Thread
NumbersOfRowsInSection is Main Thread

NumbersOfRowsInSection is NOT Main Thread
configureCell is NOT Main Thread
cellForRowAtIndexPath is NOT Main Thread
configureCell is NOT Main Thread
cellForRowAtIndexPath is NOT Main Thread
configureCell is NOT Main Thread
cellForRowAtIndexPath is NOT Main Thread
configureCell is NOT Main Thread
cellForRowAtIndexPath is NOT Main Thread
configureCell is NOT Main Thread
cellForRowAtIndexPath is NOT Main Thread
configureCell is NOT Main Thread
cellForRowAtIndexPath is NOT Main Thread
configureCell is NOT Main Thread
cellForRowAtIndexPath is NOT Main Thread
configureCell is NOT Main Thread
cellForRowAtIndexPath is NOT Main Thread
configureCell is NOT Main Thread
cellForRowAtIndexPath is NOT Main Thread
configureCell is NOT Main Thread
cellForRowAtIndexPath is NOT Main Thread

【问题讨论】:

  • 也许一些代码可能会有所帮助...你在 cellForRowAtIndexPath 中有什么?
  • @Mike 当然,我加了一些。
  • 您是否验证过您的 UI 更新正在主线程上分派;并且您的核心数据设置是使用线程限制,还是使用适当的替代方案?
  • @nzeltzer 我不确定:如果将任何内容分派到另一个线程,我不会在代码中看到它吗?或者是否有在另一个线程上自动运行的库方法?我还没有详细听说过更多的核心数据“设置”,但默认情况下它不是线程受限的吗?
  • 在大多数情况下,是的。我之所以这么问,是因为这种延迟的 UI 刷新是从主线程以外的某个线程推送更新的常见症状。

标签: uitableview core-data swift ios8


【解决方案1】:

我遇到了类似的问题。
您需要在主线程上进行任何 ui 更改。当您进行数据请求时,回调可能不在主线程上。所以要这样做:

dispatch_async(dispatch_get_main_queue()){    
    self.tableView.reloadData() // reload table/data or whatever here. However you want.
}

当您从 url 加载数据时,您将有某种回调,该回调将被发送到闭包(objc 中的一个块)。当调用该闭包时,它不能保证在主线程上。有时可能会,有时不会。为什么要运行dispatch_async 并告诉它使用dispatch_get_main_queue() 来获取主线程,您在说,在主线程上运行以下代码。所有 UI 更改都必须从主线程进行。

【讨论】:

  • 我进一步指定了问题(再次检查 EDIT)。你也是这样处理的吗?我现在正试图弄清楚如何用这些新输入来解决它......
  • 所以如果你不做任何事情,表格数据就会消失?
  • 不,在这些部分中的某些部分在全局队列上运行的情况下,会出现上面显示的问题:表中的数据在启动时已加载并显示,但随后有第二次刷新,其中文本消失 - 重新出现。只是现在表运行没有任何问题。
  • 没错。所以你自己刷新数据?
  • 如果您自己刷新数据,则不会在主线程上刷新它。你需要这样做。就像我在答案中建议的那样
【解决方案2】:

你也可以像这样重新加载 UITableView

self.tblMainTable.performSelectorOnMainThread(Selector("reloadData"), withObject: nil, waitUntilDone: true)

As I mentioned here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-31
    • 1970-01-01
    • 1970-01-01
    • 2015-01-30
    • 1970-01-01
    • 1970-01-01
    • 2015-06-01
    • 1970-01-01
    相关资源
    最近更新 更多