SEO技术

SEO技术

Products

当前位置:首页 > SEO技术 >

微信朋友圈如何通过WordPress进行网站推广并实现盈利?

96SEO 2026-02-23 14:31 12


outSu…

iOS界面刷新机制贰、浅谈UIView的刷新与绘制概述一.UIView

微信朋友圈如何通过WordPress进行网站推广并实现盈利?

CALayer1.

CALayer的一些常用属性contents属性contentGravity属性contentsScale属性maskToBounds属性contentsRect属性

二.View的布局与显示1.图像显示原理2.布局layoutSubviews()方法setNeedsLayout()方法layoutIfNeeded()方法

3.显示drawRect:方法setNeedsDisplay()方法

三.UIView的系统绘制与异步绘制流程UIView的绘制流程系统绘制异步绘制什么是异步绘制?异步绘制流程

四.总结

二、解决方案及亮点1、方案概述2、问题点3、分析过程1异步绘制时机及减少重复绘制2队列的并发和择优

三、详细设计1、设计图2、代码原理剖析写在注释1设置runloop监听及回调2创建、获取文本异步绘制队列并择优选取3异步绘制4异步下载缓存图片

五、成效举证六、核心代码范围

setNeedsLayout/setNeedsDisplay方法后这个

UIView/CALayer

_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv()。

这个函数里会遍历所有待处理的

UIView/CAlayer

_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv()QuartzCore:CA::Transaction::observer_callback:CA::Transaction::commit();CA::Context::commit_transaction();CA::Layer::layout_and_display_if_needed();CA::Layer::layout_if_needed();[CALayer

layoutSubviews];CA::Layer::display_if_needed();[CALayer

display];[UIView

//只有初始化frame的时候才会触发更新界面并不会再次触发。

如果想触发可手动调setNeedsDisplay方法。

关于setNeedsLayout、setNeedsDisplay以及layoutIfNeeded方法的说明

setNeedsLayout会触发上面的界面刷新流程runloop休眠或退出后会触发layoutSubviews方法

setNeedsDisplay会触发上面的界面刷新流程runloop休眠或退出后会触发drawRect方法

layoutIfNeeded如果有需要刷新的标记frame变化或者约束变化会触发上面的界面刷新流程runloop休眠或退出后会触发layoutSubviews方法如果没有标记不会调用layoutSubviews。

该方法一般用于Autolayout布局时及时获取各视图的frame。

UIView是我们在做iOS开发时每天都会接触到的类几乎所有跟页面显示相关的控件也都继承自它。

但是关于UIView的布局、显示、以及绘制原理等方面笔者一直一知半解只有真正了解了它的原理才能更好的服务我们的开发。

并且在市场对iOS开发者要求越来越高的大环境下对App页面流畅度的优化也是对高级及以上开发者必问的面试题这就需要我们要对UIView有更深的认知。

一.UIView

UIView一个视图UIView就是在屏幕上显示的一个矩形块比如图片文字或者视频它能够拦截类似于鼠标点击或者触摸手势等用户输入。

视图在层级关系中可以互相嵌套一个视图可以管理它的所有子视图的位置,在iOS当中所有的视图都从一个叫做UIView的基类派生而来UIView可以处理触摸事件可以支持基于Core

Graphics绘图可以做仿射变换例如旋转或者缩放或者简单的类似于滑动或者渐变的动画。

CALayer:CALayer类在概念上和UIView类似同样也是一些被层级关系树管理的矩形块同样也可以包含一些内容像图片文本或者背景色管理子图层的位置。

它们有一些方法和属性用来做动画和变换。

和UIView最大的不同是CALayer不处理用户的交互。

CALayer并不清楚具体的响应链iOS通过视图层级关系用来传送触摸事件的机制于是它并不能够响应事件即使它提供了一些方法来判断一个触点是否在图层的范围之内。

UIView

每一个UIView都有一个CALayer实例的图层属性也就是所谓的backing

layer视图的职责就是创建并管理这个图层以确保当子视图在层级关系中添加或者被移除的时候他们关联的图层也同样对应在层级关系树当中有相同的操作.

两者的关系实际上这些背后关联的图层(Layer)才是真正用来在屏幕上显示和做动画UIView仅仅是对它的一个封装提供了一些iOS类似于处理触摸的具体功能以及Core

这里引申出面试常问的一个问题为什么iOS要基于UIView和CALayer提供两个平行的层级关系呢为什么不用一个简单的层级来处理所有事情呢

原因在于要做职责分离单一职责原则这样也能避免很多重复代码。

在iOS和Mac

OS两个平台上事件和用户交互有很多地方的不同基于多点触控的用户界面和基于鼠标键盘有着本质的区别这就是为什么iOS有UIKit和UIView但是Mac

OS有AppKit和NSView的原因。

他们功能上很相似但是在实现上有着显著的区别。

把这种功能的逻辑分开并封装成独立的Core

OS之间共享代码使得对苹果自己的OS开发团队和第三方开发者去开发两个平台的应用更加便捷。

contents属性

CALayer的contents属性可以让我们为layer图层设置一张图片我们看下它的定义

object

contents;这个属性的类型被定义为id意味着它可以是任何类型的对象。

在这种情况下你可以给contents属性赋任何值你的app都能够编译通过。

但是,如果你给contents赋的不是CGImage那么你得到的图层将是空白的。

事实上你真正要赋值的类型应该是CGImageRef它是一个指向CGImage结构的指针UIImage有一个CGImage属性它返回一个CGImageRef但是要使用它还需要进行强转:

layer.contents

_Nullable)(image.CGImage);contentGravity属性

string

contentsGravity;如果我们为图层layer设置contents为一张图片那么可以使用这个属性来让图片自适应layer的大小它类似于UIView的contentMode属性但是它是一个NSString类型而不是像对应的UIKit部分那里面的值是枚举。

contentsGravity可选的常量值有以下一些

kCAGravityCenter

kCAGravityResizeAspectFill例如如果要让图片等比例拉伸去自适应layer的大小可以直接这样设置

kCAGravityResizeAspect;contentsScale属性

Defines

contentsScalecontentsScale属性定义了contents设置图片的像素尺寸和视图大小的比例默认情况下它是一个值为1.0的浮点数。

这个属性其实属于支持Retina屏幕机制的一部分它的值等于当前设备的物理尺寸与逻辑尺寸的比值。

如果contentsScale设置为1.0将会以每个点1个像素绘制图片如果设置为2.0则会以每个点2个像素绘制图片。

当用代码的方式来处理contents设置图片的时候一定要手动的设置图层的contentsScale属性否则图片在Retina设备上就显示得不正确啦。

代码如下

layer.contentsScale

mainScreen].scale;maskToBounds属性

maskToBounds属性的功能类似于UIView的clipsToBounds属性如果设置为YES则会将超出layer范围的图片进行裁剪.

contentsRect属性

contentsRect属性在我们的日常开发中用的不多它的主要作用是可以让我们显示contents所设置图片的一个子区域。

它是单位坐标取值在0到1之间。

默认值是{0,

1}这意味着整个图片默认都是可见的如果我们指定一个小一点的矩形比如{0,0,0.5,0.5},那么layer显示的只有图片的左上角也就是1/4的区域。

实际上给layer的contents赋CGImage的值不是唯一的设置其寄宿图的方法。

我们也可以直接用Core

Graphics直接绘制。

通过继承UIView并实现-drawRect:方法来自定义绘制如果单独使用CALayer那么可以实现其代理(CALayerDelegate)方法-

*)layer

inContext:(CGContextRef)ctx;在这里面进行自主绘制。

实际的方法绘制流程我们在下面进行探讨。

1.图像显示原理

在开始介绍图像的布局与显示之前我们有必要先了解下图像的显示原理也就是我们创建一个显示控件是怎么通过CPU与GPU的运算显示在屏幕上的。

这个过程大体分为六个阶段

首先一个视图由CPU进行Frame布局准备视图(view)和图层(layer)的层级关系,以及设置图层属性位置背景色边框等等。

显示view的显示图层(layer)它的寄宿图片被绘制的阶段。

所谓的寄宿图就是上面我们提到过的layer所显示的内容。

它有两种设置形式一种是直接设置layer.contents赋值一个CGImageRef;第二种是重写UIView的drawRect:或CALayerDelegate的drawLayer:inContext:方法实现自定义绘制。

注意如果实现了这两个方法会额外的消耗CPU的性能。

准备这是Core

Animation准备发送数据到渲染服务的阶段。

这个阶段主要对视图所用的图片进行解码以及图片的格式转换。

PNG或者JPEG压缩之后的图片文件会比同质量的位图小得多。

但是在图片绘制到屏幕上之前必须把它扩展成完整的未解压的尺寸通常等同于图片宽

4个字节。

为了节省内存iOS通常直到真正绘制的时候才去解码图片。

提交CPU会将处理视图和图层的层级关系打包通过IPC内部处理通信通道提交给渲染服务渲染服务由OpenGL

ES和GPU组成。

生成帧缓存渲染服务首先将图层数据交给OpenGL

ES进行纹理生成和着色生成前后帧缓存。

再根据显示硬件的刷新频率一般以设备的VSync信号和CADisplayLink为标准进行前后帧缓存的切换。

渲染

将最终要显示在画面上的后帧缓存交给GPU进行采集图片和形状运行变换应用纹理和混合最终显示在屏幕上。

注意当图层被成功打包发送到渲染服务器之后CPU仍然要做如下工作为了显示屏幕上的图层Core

Animation必须对渲染树种的每个可见图层通过OpenGL循环转换成纹理三角板。

由于GPU并不知晓Core

Animation图层的任何结构所以必须要由CPU做这些事情。

前四个阶段都在软件层面处理通过CPU第五阶段也有CPU参与只有最后一个完全由GPU执行。

而且你真正能控制只有前两个阶段布局和显示Core

Animation框架在内部处理剩下的事务你也控制不了它。

所以接下来我们来重点分析布局与显示阶段。

2.布局

布局布局就是一个视图在屏幕上的位置与大小。

UIView有三个比较重要的布局属性framebounds和center.UIView提供了用来通知系统某个view布局发生变化的方法也提供了在view布局重新计算后调用的可重写的方法。

layoutSubviews()方法

layoutSubviews():当一个视图“认为”应该重新布局自己的子控件时它便会自动调用自己的layoutSubviews方法在该方法中“刷新”子控件的布局.这个方法并没有系统实现需要我们重新这个方法在里面实现子控件的重新布局。

这个方法很开销很大因为它会在每个子视图上起作用并且调用它们相应的layoutSubviews方法.系统会根据当前run

loop的不同状态来触发layoutSubviews调用的机制,并不需要我们手动调用。

以下是他的触发时机

直接修改

的大小时会触发调用addSubview会触发子视图的layoutSubviews用户在

UIScrollView

会在UIScrollView和它的父view上被调用用户旋转设备更新视图的

constraints

这些方式都会告知系统view的位置需要被重新计算继而会调用layoutSubviews.当然也可以直接触发layoutSubviews的方法。

setNeedsLayout()方法

setNeedsLayout()方法的调用可以触发layoutSubviews,调用这个方法代表向系统表示视图的布局需要重新计算。

不过调用这个方法只是为当前的视图打了一个脏标记告知系统需要在下一次run

loop中重新布局这个视图。

也就是调用setNeedsLayout()后会有一段时间间隔然后触发layoutSubviews.当然这个间隔不会对用户造成影响因为永远不会长到对界面造成卡顿。

layoutIfNeeded()方法

layoutIfNeeded()方法的作用是告知系统当前打了脏标记的视图需要立即更新不要等到下一次run

loop到来时在更新,此时该方法会立即触发layoutSubviews方法。

当然但如果你调用了layoutIfNeeded之后并且没有任何操作向系统表明需要刷新视图那么就不会调用layoutsubview.这个方法在你需要依赖新布局无法等到下一次

run

和布局的方法类似显示也有触发更新的方法它们由系统在检测到更新时被自动调用或者我们可以手动调用直接刷新。

drawRect:方法

在上面我们提到过如果要设置视图的寄宿图除了直接设置view.layer.contents属性还可以自主进行绘制。

绘制的方法就是实现view的drawRect:方法。

这个方法类似于布局的layoutSubviews方法它会对当前View的显示进行刷新不同的是它不会触发后续对视图的子视图方法的调用。

跟layoutSubviews一样我们不能直接手动调用drawRect:方法应该调用间接的触发方法让系统在

run

中的不同结点自动调用。

具体的绘制流程我们在本文第三节进行介绍。

setNeedsDisplay()方法

这个方法类似于布局中的setNeedsLayout。

它会给有内容更新的视图设置一个内部的标记但在视图重绘之前就会返回。

然后在下一个run

loop中系统会遍历所有已标记的视图并调用它们的drawRect:方法。

大部分时候在视图中更新任何

组件都会把相应的视图标记为“dirty”通过设置视图“内部更新标记”在下一次run

loop中就会重绘而不需要显式的调用setNeedsDisplay.

UIView调用setNeedsDisplay,这个方法我们已经介绍过了它并不会立即开始绘制。

UIView

调用setNeedsDisplay实际会调用其layer属性的同名方法此时相当于给layer打上绘制标记。

在当前run

loop

将要结束的时候才会调用CALayer的display方法进入到真正的绘制当中在CALayer的display方法中,会判断layer的代理方法displayLayer:是否被实现如果代理没有实现这个方法则进入系统绘制流程否则进入异步绘制入口。

系统绘制

在系统绘制开始时在CALayer内部会创建一个绘制上下文这个上下文可以理解为CGContextRef,我们在drawRect:方法中获取到的currentRef就是它。

然后layer会判断是否有delegate没有delegate就调用CALayer的drawInContext方法如果有代理并且你实现了CALayerDelegate协议中的-drawLayer:inContext:方法或者UIView中的-drawRect:方法其实就是前者的包装方法那么系统就会调用你实现的这两个方法中的一个。

关于这里的代理我的理解是如果你直接使用的UIView那么layer的代理就是当前view你直接实现-drawRect:然后在这个方法里面进行自主绘制;

如果你用的是单独创建的CALayer那么你需要设置layer.delegate

self;

当然这里的self就是持有layer的视图或是控制器了这时你需要实现-drawLayer:inContext:方法然后在这个方法里面进行绘制。

bitmap

注意使用CPU进行绘图的代价昂贵除非绝对必要否则你应该避免重绘你的视图。

提高绘制性能的秘诀就在于尽量避免去绘制。

异步绘制

通过上面的介绍我们熟悉了系统绘制流程系统绘制就是在主线程中进行上下文的创建控件的自主绘制等这就导致了主线程频繁的处理UI绘制的工作如果要绘制的元素过多过于频繁就会造成卡顿。

而异步绘制就是把复杂的绘制过程放到后台线程中执行从而减轻主线程负担来提升UI流畅度。

异步绘制流程

从上图看异步绘制的入口在layer的代理方法displayLayer:如果要进行异步绘制我们必须在自定义view中实现这个方法在displayLayer:方法中我们开辟子线程在子线程中我们创建绘制上下文并借助Core

Graphics

相关API完成自主绘制完成绘制后生成Image图片最后回到主线程把Image图片赋值给layer的contents属性。

当然我们在日常开发中还要考虑线程的管理与绘制时机等问题使用第三方库YYAsyncLayer可以让我们把注意力放在具体的绘制上,具体的使用流程可以点这里去查看.

四.总结

我们知道当我们实现了CALayerDelegate协议中的-drawLayer:inContext:方法或者UIView中的-drawRect:方法图层就创建了一个绘制上下文这个上下文需要的大小的内存可从这个算式得出图层宽X图层高X4字节宽高的单位均为像素。

对于一个在Retina

2048X15264字节相当于12MB内存图层每次重绘的时候都需要重新抹掉内存然后重新分配。

可见使用Core

Graphics利用CPU进行绘制代价是很高的那么如何进行高效的绘图呢iOS-Core-Animation-Advanced-Techniques给出了答案我们在日常开发中完全可以使用Core

Graphics进行图形的绘制具体的方法这里就不介绍了感兴趣的可以自行去查看。

参考引用

iOS-Core-Animation-Advanced-Techniques

YYAsyncLayer

https://juejin.cn/post/6844903567610871816

iOS列表性能优化之异步绘制

https://juejin.cn/post/6901957495548608525#heading-20

一、需求背景

iOS所提供的UIKit框架其工作基本是在主线程上进行界面绘制、用户输入响应交互等等。

当大量且频繁的绘制任务以及各种业务逻辑同时放在主线程上完成时便有可能造成界面卡顿丢帧现象即在16.7ms内未能完成1帧的绘制帧率低于60fps黄金标准。

目前常用的UITableView或UICollectionView在大量复杂文本及图片内容填充后如果没有优化处理快速滑动的情况下易出现卡顿流畅性差问题。

2、需求

不依赖任何第三方pod框架主要从异步线程绘制、图片异步下载渲染等方面尽可能优化UITableView的使用提高滑动流畅性让帧率稳定在60fps。

(网上有很多优秀的性能优化博客和开源代码本方案也是基于前人的经验结合自身的理解和梳理写成demo关键代码有做注释很多细节值得推敲和持续优化不足之处望指正。

)

二、解决方案及亮点

支持异步绘制动态文本内容减轻主线程压力并缓存高度减少CPU计算

异步队列并发管理择优选取执行任务

发现UITableView首次reload会触发3次的系统问题初始开销增大待优化

2、问题点

这里简单描述下绘制原理当UI被添加到界面后我们改变Frame或更新

UIView/CALayer层次或调用setNeedsLayout/setNeedsDisplay方法均会添加重新绘制任务。

这个时候系统会注册一个Observer监听BeforeWaiting(即将进入休眠)和Exit(即将退出Loop)事件并回调执行当前绘制任务setNeedsDisplay-display-displayLayer最终更新界面。

由上可知我们可以模拟系统绘制任务的收集在runloop回调中去执行并重写layer的dispaly方法开辟子线程进行异步绘制再返回主线程刷新。

当同个UI多次触发绘制请求时怎样减少重复绘制以便减轻并发压力比较重要。

本案通过维护一个全局线程安全的原子性状态在绘制过程中的关键步骤处理前均校验是否要放弃当前多余的绘制任务。

一次runloop回调经常会执行多个绘制任务这里考虑开辟多个线程去异步执行。

首选并行队列可以满足但为了满足性能效率的同时确保不过多的占用资源和避免线程间竞争等待更好的方案应该是开辟多个串行队列单线程处理并发任务。

我们知道一个n核设备并发执行n个任务最多创建n个线程时线程之间将不会互相竞争资源。

因此不建议数量设置超过当前激活的处理器数并可根据项目界面复杂度以及设备性能适配适当限制并发开销文本异步绘制最大队列数设置如下

#define

processInfo].activeProcessorCount;//

根据处理器的数量和设置的最大队列数来设定当前队列数组的大小_limitQueueCount

processorCount

}文本的异步绘制串行队列用GCD实现图片异步下载通过NSOperationQueue实现两者最大并发数参考SDWebImage图片下载并发数的限制数6。

如何择优选取执行任务文本异步队列的选取可以自定义队列的任务数标记在队列执行任务前计算1当任务执行结束计算-1。

这里忽略每次绘制难易度的略微差异我们便可以判定任务数最少接近于最优队列。

图片异步下载任务交由NSOperationQueue处理并发我们要处理的是让同个图片在多次并发下载请求下仅生成1个NSOperation添加到queue即去重只下载一次并缓存且在下载完成后返回主线程同步渲染多个触发该下载请求的控件本案demo仅用一张图片所以这种情况必须考虑到。

三、详细设计

ADRunLoopCallBack(CFRunLoopObserverRef

observer,

enumerateObjectsUsingBlock:^(ADTask

*task,

methodForSelector:self.selector])(self.target,

self.selector);

创建观察者监听即将休眠和退出CFRunLoopObserverRef

observer

CFRunLoopObserverCreate(CFAllocatorGetDefault(),kCFRunLoopBeforeWaiting

kCFRunLoopExit,true,

设置优先级低于CATransaction(2000000)ADRunLoopCallBack,

NULL);CFRunLoopAddObserver(runloop,

observer,

kCFRunLoopCommonModes);CFRelease(observer);2创建、获取文本异步绘制队列并择优选取

(ADQueue

1、创建对应数量串行队列处理并发任务并行队列线程数无法控制if

(self.queueArr.count

self.queueArr.count;[self.queueArr

addObject:q];

1;NSLog(queue[%ld]-asyncCount:%ld,

(long)q.index,

2、当队列数已达上限择优获取异步任务数最少的队列NSUInteger

minAsync

valueForKeyPath:min.asyncCount]

ADQueue

enumerateObjectsUsingBlock:^(ADQueue

_Nonnull

1;NSLog(queue[%ld]-excute-count:%ld,

(long)q.index,

0;}NSLog(queue[%ld]-done-count:%ld,

(long)q.index,

收到新的绘制请求时同步正在绘制的线程本次取消self.status

setNeedsDisplay];

respondsToSelector:selector(asyncDrawLayer:inContext:canceled:)])

{[self

ad_getExecuteTaskQueue];__block

idADLayerDelegate

(idADLayerDelegate)self.delegate;dispatch_async(q.queue,

^{//

CGColorRetain(self.backgroundColor)

NULL;UIGraphicsBeginImageContextWithOptions(size,

opaque,

UIGraphicsGetCurrentContext();if

(opaque

CGColorGetAlpha(backgroundColor)

{CGContextSetFillColorWithColor(context,

[UIColor

whiteColor].CGColor);CGContextAddRect(context,

CGRectMake(0,

scale));CGContextFillPath(context);}if

(backgroundColor)

{CGContextSetFillColorWithColor(context,

backgroundColor);CGContextAddRect(context,

CGRectMake(0,

scale));CGContextFillPath(context);}}

CGContextRestoreGState(context);CGColorRelease(backgroundColor);}

else

CGColorRelease(backgroundColor);}

使用context绘制[delegate

ad_finishTask:q];UIGraphicsEndImageContext();return;}//

获取imageUIImage

UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();//

结束任务[[ADManager

主线程刷新dispatch_async(dispatch_get_main_queue(),

^{self.contents

(void)ad_setImageWithURL:(NSURL

*)url

{NSLocalizedFailureReasonErrorKey:

NSLocalizedStringFromTable(Expected

URL

userInfo:userInfo];completedBlock(nil,

error);}return;}//

self.imageDataDict[imageKey];if

(imageData)

stringWithFormat:%/Library/Caches/%,

NSHomeDirectory(),

url.lastPathComponent];imageData

[NSData

dataWithContentsOfFile:imagePath];if

(imageData)

*)ad_downloadImageWithURL:(NSURL

*)url

self.operationDict[imageKey];if

(!operation)

blockOperationWithBlock:^{NSLog(AsyncDraw

image

removeObjectForKey:imageKey];NSDictionary

*userInfo

{NSLocalizedFailureReasonErrorKey:

NSLocalizedStringFromTable(Failed

load

setCompletionBlock:^{NSLog(AsyncDraw

image

self.imageDataDict[imageKey];if

(!newImageData)

addOperationWithBlock:^{UIImage

*newImage

遍历渲染同个图片地址的所有控件[blockOperation.targetSet

enumerateObjectsUsingBlock:^(id

_Nonnull

ADImageView内部判断“超出可视范围放弃渲染”imageView.image

写入沙盒[newImageData

removeObjectForKey:imageKey];}];//

setValue:operation

{NSLog(异步绘制取消~);return;}UIColor

*backgroundColor

layer.bounds.size;CGContextSetTextMatrix(ctx,

CGAffineTransformIdentity);CGContextTranslateCTM(ctx,

size.height);CGContextScaleCTM(ctx,

-1);//

CGPathCreateMutable();CGPathAddRect(path,

NULL,

font,NSForegroundColorAttributeName:

textColor,NSBackgroundColorAttributeName

backgroundColor,NSParagraphStyleAttributeName

self.paragraphStyle

new]};NSMutableAttributedString

*attrStr

使用NSMutableAttributedString创建CTFrameCTFramesetterRef

framesetter

CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attrStr);CTFrameRef

frame

CTFramesetterCreateFrame(framesetter,

CFRangeMake(0,

NULL);CFRelease(framesetter);CGPathRelease(path);//

使用CTFrame在CGContextRef上下文上绘制CTFrameDraw(frame,

}2图片异步下载渲染

针对本案制作了AsyncDrawDemo是一个图文排列布局的UITableView列表类似新闻列表TestTableViewCell.m中有异步绘制和图片异步下载渲染开关

#define

本案通过YYFPSLabel观察帧率大致均值变化以及内存/CPU变化截图如下

1未开启异步前

稳定60fps后开始快速滑动至列表底部的前后对比帧率最低到1fps滑动过程异常卡顿cpu未超过40%内存占用也不多但非常耗电

2开启异步后

稳定60fps后开始快速滑动至列表底部的前后对比帧率稳定在60fps滑动过程非常流畅cpu最高超过90%内存占用到达200MB耗电小

通过以上对比得出的结论是未开启“异步绘制和异步下载渲染”虽然cpu、内存未见异常但列表滑动卡顿非常耗电开启后虽然内存占用翻倍、cpu也达到过90%但相对于4G内存和6核CPU的iPhone11来说影响不大流畅性和耗电得到保障。

由此得出结论UITableView性能优化的关键在于“系统资源充分满足调配的前提下能异步的尽量异步”否则主线程压力大引起卡顿丢帧和耗电在所难免。

补充说明当打开kOnlyShowText开关仅显示文本内容进行测试时在未打开kAsyncDraw开关前快速滑动列表帧率出现4050fps可感知快速滑动下并不流畅。

虽然UITableView性能优化主要体现在大图异步下载渲染的优化文本高度的缓存对于多核CPU设备性能提升效果确实不明显但文本异步绘制则让性能更上一层。

六、核心代码范围

DEMO地址https://github.com/stkusegithub/AsyncDraw

代码位于目录

AsyncDrawDemo/AsyncDrawDemo/Core/下

\---AsyncDraw

https://blog.csdn.net/chokshen/article/details/108714429

https://www.jianshu.com/p/bd7fdc6722ad

https://jishuin.proginn.com/p/763bfbd80508



SEO优化服务概述

作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。

百度官方合作伙伴 白帽SEO技术 数据驱动优化 效果长期稳定

SEO优化核心服务

网站技术SEO

  • 网站结构优化 - 提升网站爬虫可访问性
  • 页面速度优化 - 缩短加载时间,提高用户体验
  • 移动端适配 - 确保移动设备友好性
  • HTTPS安全协议 - 提升网站安全性与信任度
  • 结构化数据标记 - 增强搜索结果显示效果

内容优化服务

  • 关键词研究与布局 - 精准定位目标关键词
  • 高质量内容创作 - 原创、专业、有价值的内容
  • Meta标签优化 - 提升点击率和相关性
  • 内容更新策略 - 保持网站内容新鲜度
  • 多媒体内容优化 - 图片、视频SEO优化

外链建设策略

  • 高质量外链获取 - 权威网站链接建设
  • 品牌提及监控 - 追踪品牌在线曝光
  • 行业目录提交 - 提升网站基础权威
  • 社交媒体整合 - 增强内容传播力
  • 链接质量分析 - 避免低质量链接风险

SEO服务方案对比

服务项目 基础套餐 标准套餐 高级定制
关键词优化数量 10-20个核心词 30-50个核心词+长尾词 80-150个全方位覆盖
内容优化 基础页面优化 全站内容优化+每月5篇原创 个性化内容策略+每月15篇原创
技术SEO 基本技术检查 全面技术优化+移动适配 深度技术重构+性能优化
外链建设 每月5-10条 每月20-30条高质量外链 每月50+条多渠道外链
数据报告 月度基础报告 双周详细报告+分析 每周深度报告+策略调整
效果保障 3-6个月见效 2-4个月见效 1-3个月快速见效

SEO优化实施流程

我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:

1

网站诊断分析

全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。

2

关键词策略制定

基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。

3

技术优化实施

解决网站技术问题,优化网站结构,提升页面速度和移动端体验。

4

内容优化建设

创作高质量原创内容,优化现有页面,建立内容更新机制。

5

外链建设推广

获取高质量外部链接,建立品牌在线影响力,提升网站权威度。

6

数据监控调整

持续监控排名、流量和转化数据,根据效果调整优化策略。

SEO优化常见问题

SEO优化一般需要多长时间才能看到效果?
SEO是一个渐进的过程,通常需要3-6个月才能看到明显效果。具体时间取决于网站现状、竞争程度和优化强度。我们的标准套餐一般在2-4个月内开始显现效果,高级定制方案可能在1-3个月内就能看到初步成果。
你们使用白帽SEO技术还是黑帽技术?
我们始终坚持使用白帽SEO技术,遵循搜索引擎的官方指南。我们的优化策略注重长期效果和可持续性,绝不使用任何可能导致网站被惩罚的违规手段。作为百度官方合作伙伴,我们承诺提供安全、合规的SEO服务。
SEO优化后效果能持续多久?
通过我们的白帽SEO策略获得的排名和流量具有长期稳定性。一旦网站达到理想排名,只需适当的维护和更新,效果可以持续数年。我们提供优化后维护服务,确保您的网站长期保持竞争优势。
你们提供SEO优化效果保障吗?
我们提供基于数据的SEO效果承诺。根据服务套餐不同,我们承诺在约定时间内将核心关键词优化到指定排名位置,或实现约定的自然流量增长目标。所有承诺都会在服务合同中明确约定,并提供详细的KPI衡量标准。

SEO优化效果数据

基于我们服务的客户数据统计,平均优化效果如下:

+85%
自然搜索流量提升
+120%
关键词排名数量
+60%
网站转化率提升
3-6月
平均见效周期

行业案例 - 制造业

  • 优化前:日均自然流量120,核心词无排名
  • 优化6个月后:日均自然流量950,15个核心词首页排名
  • 效果提升:流量增长692%,询盘量增加320%

行业案例 - 电商

  • 优化前:月均自然订单50单,转化率1.2%
  • 优化4个月后:月均自然订单210单,转化率2.8%
  • 效果提升:订单增长320%,转化率提升133%

行业案例 - 教育

  • 优化前:月均咨询量35个,主要依赖付费广告
  • 优化5个月后:月均咨询量180个,自然流量占比65%
  • 效果提升:咨询量增长414%,营销成本降低57%

为什么选择我们的SEO服务

专业团队

  • 10年以上SEO经验专家带队
  • 百度、Google认证工程师
  • 内容创作、技术开发、数据分析多领域团队
  • 持续培训保持技术领先

数据驱动

  • 自主研发SEO分析工具
  • 实时排名监控系统
  • 竞争对手深度分析
  • 效果可视化报告

透明合作

  • 清晰的服务内容和价格
  • 定期进展汇报和沟通
  • 效果数据实时可查
  • 灵活的合同条款

我们的SEO服务理念

我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。

提交需求或反馈

Demand feedback