意外的表重新加载/刷新有一些延迟 [英] Unintended table reload/refresh with some delay

查看:142
本文介绍了意外的表重新加载/刷新有一些延迟的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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


  1. 如果我不交互,只是等待,表视图迅速刷新大约10秒(单元格变为空白,并在半秒内再次用相同的文本填充)。


  2. 如果我开始了,那么我可以点击命名的单元格并转发到详细视图,我可以回去选择任何其他。立即交互,像通常一样,我必须点击一个单元格两次,然后才被转发到详细视图。当在很短的时间内回到概览时,我发现我的表视图只填充了刚才点击的一个单元格,其余的都是空白。





  • 然后,我可以再等待5-15秒,之后一切都会自动刷新>
  • 我可以点击那些空白单元格,然后立即再次显示,而 - 当然 - 我被再次转发到详细视图或

  • 如果我在细节视图上站了更长时间,让我们说阅读一些博客,然后回来,所有单元格是可见的,因为有足够的时间这个奇怪的刷新发生在同时


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




如果这是一个完全未知的问题,您必须查看一些代码进一步调查,我很高兴与您分享。但是现在我还没有看到一点,因为它或多或少是使用表视图时实现的基本代码。我对核心数据相当新,可能已经监督的东西,但没有注意到目前为止。
我会非常感谢一些帮助,因为我通常调查很长时间之前问,但这一次真的没有线索,可能的原因。



编辑:



可能很重要的一点是,我在Xcode中启动了Master-Detail Application它提供的方法自动使用核心数据(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 +作者!
}

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



当我重新运行应用程序第二次和更多,过程如下:核心数据已经有一些值,所以单元格直接配置(日志: _是主线程)。然后,如果有Internet连接,则删除(在viewDidLoad中)所有核心数据对象,再次加载json数据,将对象放入核心数据并再次创建单元格。这个日志的第二部分现在又是 _不是主线程。如果我现在没有互联网连接运行应用程序,第二部分不会被触发,只是第一个单元格配置 _是主线程发生。



这种行为的任何直接解释?



什么是正确的(优雅的)对于主线程在任何情况下的问题?它与模板的内置NSFetchedResultsController有什么关系,或者一些任务被自动分派到全局队列是正常的吗?



日志(app builds for the 第一次,10个单元格):

  2014-09-08 13:04:54.821博客3682:193346] 17545849:_UIScreenEdgePanRecognizerEdgeSettings.edgeRegionSize = 13.000000 
2014-09-08 13:04:54.823博客读者[3682:193346] 17545849:_UIScreenEdgePanRecognizerEdgeSettings.edgeRegionSize = 13.000000
NumbersOfRowsInSection是主线程
NumbersOfRowsInSection是主线程

NumbersOfRowsInSection不是主线程
configureCell不是主线程
cellForRowAtIndexPath不是主线程
configureCell不是主线程
cellForRowAtIndexPath是不是主线程
configureCell不是主线程
cellForRowAtIndexPath不是主线程
configureCell不是主线程
cellForRowAtIndexPath不是主线程
configureCell不是主线程
cellForRowAtIndexPath不是主线程
configureCell不是主线程
cellForRowAtIndexPath不是主线程
configureCell不是主线程
cellForRowAtIndexPath不是主线程
configureCell是不是主线程
cellForRowAtIndexPath不是主线程
configureCell不是主线程
cellForRowAtIndexPath不是主线程
configureCell不是主线程
cellForRowAtIndexPath不是主线程


解决方案



你需要在主线程上做任何ui更改。当你做一个数据请求,回调可能不在主线程。所以要做这样的事情:

  dispatch_async(dispatch_get_main_queue()){
self.tableView.reloadData )//重新加载表/数据或任何这里。随你怎么便。
}

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


Xcode 6 - beta 6/7: I've created a iOS 8 (Swift) blog reader app with an overview (table view) and a detail view (web view) screen. If there's internet connection the app, when starting up, loads the actual json data from the blog and saves it as entity objects into core data. The table view that is shown first then fills its cells with those objects from core data. The cells, containing title and subtitle, are fully loaded like expected. Everything seems to work fine but...

  1. If I don't interact and just wait, the table view quickly refreshes after around 10 seconds (cells get blank and are filled with the same text again within half a second). After that everything works just fine, I can click the named cells and being forwarded to detail view, I can go back and chose any other.

  2. If I start interacting immediately, like one normally does, I have to click a cell twice before being forwarded to the detail view. When going back to the overview within little time I find my table view filled just with the one cell I just tapped before, the rest are blanks.

  • Either I can then wait for another 5-15 seconds before everything refreshes automatically (and from that point on work fine) or
  • I can tap those blank cells which get then visible again immediately, whereas - of course - I'm being forwarded again to the detail view or
  • If I had stood for longer on the detail view, let's say reading some of the blog, and then go back, all cells are visible as there was enough time for this strange refresh taking place in the meanwhile

  • As a note: If there is no internet connection the app successfully loads the objects from core data but the problem mentioned remains. So, anyway, I have to wait till this "second refresh" took place before the app runs like I want it too.

If it's a completely unknown problem and you have to see some of the code for further investigation, I'm happy to share it. But right now I haven't seen a point as it's more or less the basic code implemented when using table views. I'm fairly new to core data and may have overseen something but not noticed so far. I'd be very thankful for some help as I usually investigate quite long time before asking but this time really have no clue what the reason could be.

EDIT:

It may be important to add that I started the app with the "Master-Detail Application" template in Xcode and make us of the methods it provides to fill the cells automatically with the proper entity objects from core data (NSFetchedResultsController). Some part of the code that could give a hint where to investigate further (please tell me, if more code is needed):

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!
}

EDIT 2:

Thanks to the input nzeltzer I think I've found the point: The problem above occurs just when some parts of the code run on global (instead of main) thread. So I did some testing: The console output at the bottom shows the NSThread.isMainThread() results when the app builds for the first time.

When I rerun the app a second time and more, the process is the following: Core data already has some values so the cells are configured directly (Log: _ is Main Thread). Then, in case there is internet connection it is deleting (in the viewDidLoad) all the core data objects, loads the json data again, puts the objects to core data and creates the cells a second time. This second part of the Log is now again _ is NOT Main Thread. If I run the app now without internet connection, the second part doesn't get triggered and just the first cell configuration with _ is Main Thread takes place.

Any straight forward explanation for that behavior?

What would be the right (elegant) approach to dispatch those parts that might be responsible for the problem on main thread in any case? Does it have anything to do with the template's built-in NSFetchedResultsController or is it just normal that some tasks are dispatched to global queues automatically?

Log (app builds for the first time, 10 cells):

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

解决方案

I had a similar issue.
You need to do any ui changes on the main thread. When you do a data request, the callback may not be on the main thread. So to do that do something like this:

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

When you load data from a url, you are going to have some sort of callback which will be sent to a closure (a block in objc). When that closure is called it is not guaranteed to be on the main thread. Sometimes it might be and sometimes it will not be. Why running dispatch_async and telling it to grab the main thread with dispatch_get_main_queue() you are saying, run the following code on the main thread. All UI changes must be made from the main thread.

这篇关于意外的表重新加载/刷新有一些延迟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆