整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

UICollectionView的数据预加载及图片加载逻辑的优化

原文

主题 iOS开发 C语言

当App中使用了 以瀑布流的形式来呈现数据时,站在用户的角度,用户在自上至下一页一页浏览这些内容的过程中,当用户感到滑动很流畅自然,每页内容从无到有需要用户等待的时间很短甚至几乎感觉不到,那么 才会带给用户一个很好的体验。本文介绍了为了达到这两个目的所作出的一些客户端的优化。

数据的预加载

数据预加载的目的是不必等到用户某一时刻浏览到的末尾了,也即本地已经没有更多数据展示了才去发请求拿下一页数据,而是有一个预判,用户就快要看完本地的数据了,可以向Server要下一页数据了!

为了实现预加载,最开始的方案是在UI层面的预判。根据 的基类是 ,大致思路是对于沿竖直方向滚动的,考察它的 .y 和 .height ,结合的 frame.size.height ,可以计算全部内容底下还有多高没展示出来,如果高度小于我们预先设定的阈值(用户快滑到底了),那么就触发加载下一页的请求。

这样做似乎没什么问题,但是仔细想想,其实并不优雅。一方面,一旦有UI调整的需求,每行的高度有调整时,我们也要去调整阈值,来决定是否去请求下一页数据;另一方面,App中不同场景下的每行高度不同,需要根据不同场景去Tuning,找出合适的阈值。

后来很自然想到在逻辑上进行预判,也就是我们现在使用的方案。

每个Cell都需要一个数据模型对象(Data Object,下称DTO)来支持它的显示,通常客户端拿到的服务端返回的数据后,做一系列的解析,得到一个一个DTO,用以支持的展示。到代码层面DTO们被保存在一个数组里,任意时刻在正确的状态下 的总Cell数量应该跟当前本地DTO的个数相等,Cell跟DTO是一一对应的关系, 数据的预加载本质上就是DTO的预加载 。

用户在滚动 时,当 根据预定的配置觉得它该展示某行某列的Cell时,会向它的[2]发送 :th: 消息[3],询问那行那列该展示什么,这个方法返回一个Cell对象, 拿到这个Cell后就把它展示在相应位置。通常这个方法中要做的重要事情就是去上文提到的保存DTO的数组中根据Cell的行列索引找到这个Cell对应的DTO,根据DTO对Cell配置一番,返回给 。

顺着这个思路,在这个方法中可以知道当前 需要展示的Cell的索引,由于Cell跟DTO是一一对应的关系,那我们也知道了当前需要的DTO在总数据模型对象中的索引,当剩下的数据模型对象不够支持一页的显示时,就去请求下一页。

表达的可能有点抽象,假设请求一次Server返回20个DTO,过程可以更形象化一点:

- : 数据源数据源,用户滑到第181个Cell要露出来了,快给我!

- : 好的,我首先要去拿第181个Cell对应的DTO,根据这个配置好一个Cell给你去展示!

等等,你都已经展示到第181个Cell了啊!我发现DTO目前本地总共只有200个,200 - 181 = 19 < 20不够支持你展示下一页所需要的20个Cell了,我先发起一个异步请求,去拿新一页的DTO!

关键代码,很简单:

= .count; // 目前本地有的DTO数量

= .row; // 当前需要的Cell索引,也即当前需要的数据模型索引

if ( - < 19) {

[self ];

要注意的问题是要做好防止重复发送请求的保护工作。

图片加载逻辑优化

当 的每个Cell都需要展示一个(或多个)图片时,在上文提到的根据DTO配置Cell过程中,会根据DTO中指定的图片的URL,发送一个异步的图片请求,等到图片请求完毕了,再把图片展示到对应的Cell上(当然,可以把这一切交给 : )。

或许你会问,加载图片已经是异步了啊,我还要优化什么?不,这远远不够。在实际的测试中,这种朴素的做法依然会带来明显的滑动过程的卡顿。使用进行profile发现,在滑动过程中始终会丢那么15帧左右,不能忍!

再回到 继承自 上来。通过 的,我们能感知到滑动过程中的各种关键状态,包括用户的手是否正在拖拽,以及是否正在滑动、减速等等,这就是我们优化的秘密武器!

那么,本着不该做的事情不要做,或者等到不得不做的时候再做的原则,让我们分析用户在滑动的过程中有哪些地方可以细抠。

加载逻辑正确图片程序_页面加载逻辑_图片预加载程序的正确逻辑

用户在滑动(拖拽)时(手与屏幕正在接触),很有可能是用户在认真逐个浏览每个Cell,要去加载当前可见Cell的图片

用户滑动结束后,手离开了屏幕,并引发了减速时, 预判 减速结束后静止时的状态,对于那些将来静止时用户可见的Cell,提前去加载它们的图片;对于那些只是“昙花一现”的Cell,即它们只是在减速的过程中出现那么一刹那,就被“顶”上去了,只加载这些Cell中图片在本地有缓存的图片(从内存中加载,不值得去发网络请求,即使是异步的也不值得)

减速结束后,处于静止状态,加载当前全部可见Cell的图片

OK,那么来看我们怎么实现它。

对于的每个Cell,我们给它添加一个异步加载图片的方法 。直接上关键代码,看了便知。

// 将来静止时可见的区域,同时也是标识当前是正在被用户拖拽还是已经被拖拽完毕并正在减速

@ (, strong) CGRect *;

#pragma mark -

- ( *):( *) th:( *) {

// ....

[self :cell :];

// ....

#pragma mark -

- (void)ragging:( *) {

self. = nil;

[self ells];

- (void)gging:( *) :(CGPoint) :(inout CGPoint *) {

self. = (->x, ->y, .frame.size.width, .frame.size.height);

- (void):( *) {

self. = nil;

[self ells];

#pragma mark - Decide to Load Image For Cells

- (void):( *)cell

:( *) {

// Cell的是指派给Cell的新的图片URL,在根据Cell的DTO配置Cell时为其赋值

if (!cell.) {

return;

// Cell的是Cell的当前正在显示的图片URL

if (![cell. :cell.] || cell.derNow) {

*manager = [ ];

*attr = [self. :];

CGRect = attr.frame;

BOOL = YES;

// 如果正在减速而且当前Cell的frame不在将来滑动停止后的可见区域

if (self. && !(self.., )) {

// 那么只有Cell的在内存的缓存中,才去加载它

* = [ ];

*key = [manager :[NSURL :cell.]];

if (![ ForKey:key]) {

= NO;

if () {

[cell ];

- (void)ells {

NSArray * = [self. ];

for ( *cell in ) {

* = [self. :cell];

[self :cell :];

做了这些努力后,再去profile一下,发现网速良好情况下滑动时帧率只丢了那么1、2帧,而且滑动起来无明显卡顿!

要么不做,要么做绝

哈哈,这个有点狠啊,颇有朱元璋的风格。

做了这么多后,我们发现,数据预加载完毕后,向发送 消息通知它数据模型变化时,就在这一瞬间,还是会导致卡顿那么一下下。

好吧不能忍,封装一个我们自己的 方法,在这里简单的hold住reload,根据上文中的 属性的标记作用,当且仅当在减速停止后,再去真正向它发送 消息。在这里仅提供思路,不做赘述了。

此外,在开发中,我们把这一系列的方法以 类的形式做一个封装,这样不管谁是的或者都可以从容应对。

数据结构——关键路径

——本节内容为王道考研《数据结构》P67视频内容笔记。

目录

一、基本概念 1.AOE网

在带权有向图中,以顶点表示事件,以有向边表示活动,以边上的权值表示完成该活动的开销(如完成活动需要的时间),称之为用边表示活动的网络,简称AOE网。

(1)在AOE网中仅有一个入度为0的顶点,称为开始顶点(源点),它表示整个工程的开始;

(2)也仅有一个出度为0的顶点,称为结束顶点(汇点),它表示整个工程的结束。

关键路径上可以有虚假活动_虚假交易90天报名活动_建宁县有房产证可以上小学吗

2.AOE网的性质

(1)只有在某顶点所代表的事件发生后,从该顶点出发的各有向边所代表的活动才能开始;

(2)只有在进入某顶点的各有向边所代表的活动都已结束时,该顶点所代表的事件才能发生,另外有些活动是可以并行进行的。

3.关键路径

从源点到汇点的有向路径可能有多条,所有路径中,具有最大路径长度的路径称为关键路径,而把关键路径上的活动称为关键活动。

完成整个工程的最短时间就是关键路径的长度,若关键活动不能按时完成,则整个工程的完成时间就会延长。

虚假交易90天报名活动_建宁县有房产证可以上小学吗_关键路径上可以有虚假活动

4.最早最晚时间

(1)事件vk的最早发生时间ve(k):决定了所有从vk开始的活动能够开工的最早时间;

(2)活动ai的最早开始时间e(i):指该活动弧的起点所表示的事件的最早发生时间;

(3)事件vk的最迟发生时间vl(k):指在不推迟整个工程完成的前提下,该事件最迟必须发生的时间;

(4)活动ai的最迟开始时间l(i):指该活动弧的终点所表示事件的最迟发生时间与该活动所需时间之差;

(5)活动ai的时间余量:d(i)=l(i)-e(i),表示在不增加完成整个工程所需总时间的情况下,活动ai可以拖延的时间;

(6)若一个活动的时间余量为0,则说明该活动必须要如期完成,d(i)=0即l(i)=e(i)的活动ai是关键活动,由关键活动组成的路径就是关键路径。

二、求关键路径 1.步骤

(1)求所有事件的最早发生时间ve();

(2)求所有事件的最迟发生时间vl();

(3)求所有活动的最早发生事件e();

(4)求所有活动的最迟发生时间l();

虚假交易90天报名活动_关键路径上可以有虚假活动_建宁县有房产证可以上小学吗

(5)求所有活动的时间余量d();

(6)d(i)=0的就是关键活动,所有关键活动组成的路径即为关键路径。

2.举例

虚假交易90天报名活动_关键路径上可以有虚假活动_建宁县有房产证可以上小学吗

建宁县有房产证可以上小学吗_虚假交易90天报名活动_关键路径上可以有虚假活动

虚假交易90天报名活动_关键路径上可以有虚假活动_建宁县有房产证可以上小学吗

虚假交易90天报名活动_建宁县有房产证可以上小学吗_关键路径上可以有虚假活动

关键路径上可以有虚假活动_虚假交易90天报名活动_建宁县有房产证可以上小学吗

三、关键活动/路径特性

1.若关键活动耗时增加,则整个工程的工期将增长;

2.缩短关键活动的时间,可以缩短整个工程的工期;

3.当缩短到一定程度时,关键活动可能会变成非关键活动;

4.可能有多条关键路径,只提高一条关键路径上的关键活动速度并不能缩短整个工程的工期,只有加快那些包括在所有关键路径上的关键活动才能达到缩短工期的目的。