美文网首页
多线程操作数据源引起的tableview刷新问题

多线程操作数据源引起的tableview刷新问题

作者: 辣条少年J | 来源:发表于2019-10-15 22:18 被阅读0次

ios table刷新问题

在公司做一个网盘的项目,包括ios端和mac端。其中传输列表是比较麻烦的事情,逻辑是这样的,文件的传输信息和请求任务放在数据源datalist里,请求任务nsurlsession回调传输情况更新传输进度并计算出速率等显示信息,文件传输成功后需要对相应的item进行删除并更新,问题出现在这里,举个例子,当下载item A刚好下载完成后删除该item并使用[table reloadData]这种方式刷新,此时下载item B也下载完成,删除item B,此时第一次刷新正在进行, 这样就会导致数据源错误的问题。

解决方案:

要做到传输一个就删除一个item,解决这个问题的思路应该满足两个条件,第一,能够监听到table何时刷新完成,第二,在进行刷新时对删除数据源操作进行加锁。

方法一

table函数laytoutIfNeeded会强制重绘并等待完成,可以在刷新代码后调用此函数,该函数是同步函数,在该操作执行完成后可以保证此时table已经刷新完毕。实践时无法保证layoutifneeded监听到table刷新完毕事件

[self.tableview reloadData]
[self.tableview layoutIfNeeded]

方法二

监听tableview的加载完成信息,tableview的layoutsubviews执行后便是tableview加载完成,我们可以这样操作,即在第一次刷新时添加信号量,第二次删除数据源时等待,在第一次刷新完成后释放信号量。这样操作可以达到上面提到的两种要求的效果。写了个demo展示该逻辑,逻辑与下面代码同:

    func task(){
        let semaphore = DispatchSemaphore.init(value: 0)
        DispatchQueue.global().async {
            sleep(5);
            self.dataList.remove(at: self.dataList.count-1)
            print("我是刷新1");
            DispatchQueue.main.async {
                self.tableView?.reloadDataWithCompletion {
                    print("加载1完成")
                    semaphore.signal()
                }
            }
        }
        DispatchQueue.global().async {
            sleep(5)
            usleep(useconds_t(0.002*1000000))
            semaphore.wait()
            self.dataList.remove(at: self.dataList.count-1)
            print("我是刷新2");
            DispatchQueue.main.async {
                self.tableView?.reloadDataWithCompletion {
                    print("加载2完成")
                }
            }
        }
    }

两个global.async任务模拟传输任务,sleep模拟传输需要时间,第一次删除数据源刷新table,刷新完成后释放信号量,此时第二次刷新才能进入同样的流程。下面这个函数更能模拟这个流程:

    func simulate_transList(){
        for i in 1...10{
            DispatchQueue.global().async {
                if(self.lock==nil){
                    self.lock=DispatchSemaphore.init(value: 0)
                }
                else{
                    self.lock?.wait()
                }
                self.dataList.remove(at: self.dataList.count-1)
                print("刷新\(i)开始 \(Utils.getDateTime())");
                DispatchQueue.main.async {
                    self.tableView?.reloadDataWithCompletion {
                        print("刷新\(i)完成 \(Utils.getDateTime())")
                        self.lock?.signal()
                    }
                }
            }
        }
    }

第二种方式可以保证table reload的时候不会因为数据源的变化而造成错误,但是实际操作时可能会出现刷新顺序不是按照for循环的顺序执行的问题,猜测是由于几次操作同时进入刷新。
那这样我们可以整理下思路了,子类化tableview并实现重写layoutviews事件,定义一个全局信号量,在文件传输完成时进行wait操,tableview刷新完毕后进行signal操作,wait一次signal一次,这样能起到刷新时对正在刷新的数据源的加锁功能。

相关文章

  • 多线程操作数据源引起的tableview刷新问题

    ios table刷新问题 在公司做一个网盘的项目,包括ios端和mac端。其中传输列表是比较麻烦的事情,逻辑是这...

  • UI数据源同步

    数据源同步问题多线程对共享数据的访问,需要考虑数据源的同步问题,如何解决tableView在多线程环境下的修改或者...

  • iOS中UITableView reloadData 不能刷新的

    我在项目中遇到了1次进入页面刷新tableview 没有问题,然后我点击改变数据源后刷新, tableview ...

  • IOS面试题(TableView) ----- 数据源同步

    问题: 请说一下tableview的数据源同步问题, 都有哪些解决方法 或者问: 多线程对tableview同一...

  • 第二章、UI视图相关

    一、UITableView相关的数据源同步问题,即如何在tableview解决多线程情况下,数据的处理? 1、并行...

  • UITableView数据源同步

    UITableView多线程操作会导致数据源不同步问题,比如删除操作的同时loadMore操作返回 并发访问 数据...

  • iOS- UITableView数据源同步

    问题多线程下,修改tableview的数据源,数据同步问题的解决方案? 应用场景:在某些新闻类app中,当有用户做...

  • Table view 刷新某个值

    1. 如何刷新tableView中数据源某个key值? if(_dataSouce.count!=0){ ...

  • 02-UI视图

    UI视图内容 UITableView重用机制数据源的多线程操作(数据源同步问题) 事件传递&视图响应 视图显示原理...

  • UITableView之局部刷新的正确使用姿势

    局部刷新 苹果提供了较为丰富的tableView数据源操作方法,想必大家早已是信手拈来.使用这些方法不仅可以精细的...

网友评论

      本文标题:多线程操作数据源引起的tableview刷新问题

      本文链接:https://www.haomeiwen.com/subject/bdzxmctx.html