iOS Instrument使用之Core Animation(图形性能)

本文详细介绍了iOS Instrument中Core Animation模板的使用,包括Debug Options的各种功能,如Color Blended Layers(图层混合)、Color Hits Green and Misses Red(图层缓存)等,帮助开发者识别和优化图形性能问题,减少离屏渲染和GPU资源消耗,提升应用性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. Core Animation(图形性能) #

Core Animation: 离屏渲染,图层混合等GPU耗时。
英文描述: this template measures application graphics performace as well as cpu usage of a process via time profiling

该模块对通过时间来分析APP的图形性能处理情况,同time profiling分析一个进程的CPU使用情况类似

CoreAnimation系要注意的一点是必须是真机调试,用于调试离屏渲染,绘图,动画,等操作。

这里写图片描述

2. Debug Options #

这里写图片描述

1、Color Blended Layers 图层混合##

首先我们要明白像素的概念,屏幕上每一个点都是一个像素,像素有R、G、B三种颜色构成(有时候还带有alpha值)。如果某一块区域上覆盖了多个layer,最后的显示效果受到这些layer的共同影响。举个例子,上层是蓝色(RGB=0,0,1),透明度为50%,下层是红色(RGB=1,0,0)。那么最终的显示效果是紫色(RGB=0.5,0,0.5)。这种颜色的混合(blending)需要消耗一定的GPU资源,因为实际上可能不止只有两层。如果只想显示最上层的蓝色,可以把它的透明度设置为100%,这样GPU会忽略下面所有的layer,从而节约了很多不必要的运算。<

//

这个选项基于渲染程度对屏幕中的混合区域进行绿到红的高亮(也就是多个半透明图层的叠加)。由于重绘的原因,混合对GPU性能会有影响,同时也是滑动或者动画帧率下降的罪魁祸首之一。

GPU每一帧可以绘制的像素有一个最大限制(就是所谓的fill rate),这个情况下可以轻易地绘制整个屏幕的所有像素。但是如果由于重叠图层的关系需要不停地重绘同一区域的话,掉帧就可能发生了。

GPU会放弃绘制那些完全被其他图层遮挡的像素,但是要计算出一个图层是否被遮挡也是相当复杂并且会消耗处理器资源。同样,合并不同图层的透明重叠像素(即混合)消耗的资源也是相当客观的。所以为了加速处理进程,不到必须时刻不要使用透明图层。任何情况下,你应该这样做:

给视图的backgroundColor属性设置一个固定的,不透明的颜色
设置opaque属性为YES
如果用到了图像,尽量避免透明除非非常必要。如果图像要显示在一个固定的背景颜色或是固定的背景图之前,你没必要相对前景移动,你只需要预填充背景图片就可以避免运行时混色了。
如果是文本的话,一个白色背景的UILabel(或者其他颜色)会比透明背景要更高效。

Color Blended Layers”正是用于检测哪里发生了图层混合,并用红色标记出来。因此我们需要尽可能减少看到的红色区域。一旦发现应该想法设法消除它。开始调试后勾选这个选项,我们在手机上可以看到如下的场景:

这里写图片描述

2. Color Hits Green and Misses Red : 图层缓存##

光栅化是将一个layer预先渲染成位图(bitmap),然后加入缓存中。如果对于阴影效果这样比较消耗资源的静态内容进行缓存,可以得到一定幅度的性能提升。demo中的这一行代码表示将label的layer光栅化:
label.layer.shouldRasterize = YES;

它表示如果命中缓存则显示为绿色,否则显示为红色,显然绿色越多越好,红色越少越好。

注意:光栅化的核心在于缓存的思想。

这是因为layer进行光栅化后渲染成位图放在缓存中。当屏幕出现滑动时,我们直接从缓存中读取而不必渲染,所以会看到绿色。当新的label出现时,缓存中没有个这个label的位图,所以会变成红色。第三点比较关键,缓存中的对象有效期只有100ms,即如果在0.1s内没有被使用就会自动从缓存中清理出去。这就是为什么停留一会儿再滑动就会看到红色。

当我们使用得当时,光栅化可以提供很大的性能优势,但是一定要避免作用在内容不断变动的图层上,否则它缓存方面的好处就会消失,而且会让性能变的更糟。

3、Color Copied Images 图片格式检测##

颜色格式: 像素在内存中的布局和它在磁盘中的存储方式并不相同。考虑一种简单的情况:每个像素有R、G、B和alpha四个值,每个值占用1字节,因此每个像素占用4字节的内存空间。一张1920*1080的照片(iPhone6 Plus的分辨率)一共有2,073,600个像素,因此占用了超过8Mb的内存。但是一张同样分辨率的PNG格式或JPEG格式的图片一般情况下不会有这么大。这是因为JPEG将像素数据进行了一种非常复杂且可逆的转化。

CPU主要处理两件事:
(1)把图片从PNG或JPEG等格式中解压出来,得到像素数据
(2)如果GPU不支持这种颜色各式,CPU需要进行格式转换
比如应用中有一些从网络下载的图片,而GPU恰好不支持这个格式,这就需要CPU预先进行格式转化。

检测这种实时的格式转化,如果有则会将图片标记为蓝色

这里写图片描述

如果GPU不支持当前图片的颜色格式,那么就会将图片交给CPU预先进行格式转化,并且这张图片标记为蓝色。那么GPU支持什么格式呢?苹果的GPU只解析32bit的颜色格式,如果使用Color Copied Images去调试发现是’蓝色’,这个时候你也可以去找你们的UI眉眉了~

知识扩展:32bit指的是图片颜色深度,用“位”来表示,用来表示显示颜色数量,例如一个图片支持256种颜色,那么就需要256个不同的值来表示不同的颜色,也就是从0到255,二进制表示就是从00000000到11111111,一共需要8位二进制数,所以颜色深度是8。通常32bit色彩中使用三个8bit分别表示R红G绿B蓝,还有一个8bit常用来表示透明度(Alpha)。

4、Color Misaligned Images 图片尺寸是否匹配##

在项目中,我们网络请求图片,大小不一,但是展示的UIImageView有时候是固定大小。这时候我们就需要图片的缩放了。图片的缩放需要占用时间,因此我们要尽可能保证无论是本地图片还是从网络或取得图片的大小,都与其frame保持一致。

如果图片需要缩放则标记为黄色,如果没有像素对齐则标记为紫色。勾选上这个选项并进行调试,可以看到如下场景:

这里写图片描述

5、Color Offscreen-Rendered Yellow: 圆角,图层蒙版,阴影,重绘##

离屏渲染表示渲染发生在屏幕之外。离屏渲染意味着把渲染结果临时保存,等用到时再取出,因此相对于普通渲染更占用资源。

选项“Color Offscreen-Rendered Yellow”会把需要离屏渲染的地方标记为黄色,大部分情况下我们需要尽可能避免黄色的出现。离屏渲染可能会自动触发,也可以手动触发。以下情况可能会导致触发离屏渲染:

这里写图片描述

1、重写drawRect方法;(自动触发离屏渲染)
2、有mask或者是阴影(layer.masksToBounds, layer.shadow*),模糊效果也是一种mask;(自动触发离屏渲染)
3、layer.shouldRasterize = true;(手动开启离屏渲染)

设置cornerRadius本身并不会导致离屏渲染,但很多时候它还需要配合layer.masksToBounds = true使用。根据之前的总结,设置masksToBounds会导致离屏渲染。解决方案是尽可能在滑动时避免设置圆角,如果必须设置圆角,可以使用光栅化技术将圆角缓存起来:

(1)drawRect:方法
(2)layer.shadow
(3)layer.allowsGroupOpacity or layer.allowsEdgeAntialiasing
(4)layer.shouldRasterize
(5)layer.mask
(6)layer.masksToBounds && layer.cornerRadius

6、Color Compositing Fast-Path Blue 快速路径##

离屏渲染的最后一步是把此前的多个路径组合起来。如果这个组合过程能由CPU完成,就会大量减少GPU的工作。这种技术在绘制地图中可能用到。

标记由硬件绘制的路径为蓝色,蓝色越多越好,可以对直接使用OpenGL绘制的图层进行高亮。没有对OpenGL有过多的研究,所以这里没办法给出demo,大家只需要记住蓝色越多越好就ok。

这个选项会对任何直接使用OpenGL绘制的图层进行高亮。如果仅仅使用UIKit或者Core Animation的API,那么不会有任何效果。如果使用GLKView或者CAEAGLLayer,那如果不显示蓝色块的话就意味着你正在强制CPU渲染额外的纹理,而不是绘制到屏幕。

7、Flash updated Regions : 重绘区域##

这个选项会对重绘的内容高亮成黄色,重绘就是指使用Core Graphics绘制,绘制会损耗一定的性能,因此重绘区域应该越小越好。

8、Color Immediately(颜色刷新频率)##

当执行颜色刷新的时候移除10ms的延迟,因为可能在特定情况下你不需要这些延迟,所以使用此选项加快颜色刷新的频率。不过一般这个调试选项我们是用不到的。

9、Color No-Standard Surface Formats##

就是打开这个选项,某些Label和Button的背景颜色都会出现银白色,但是不是必先现的,有些Label和Button依然正常颜色背景。其他ImageView等控件是不会出现银白色的背景颜色。

<think>好的,我现在需要回答用户关于iOS开发中可以采取的具体性能优化措施的问题。用户之前已经询问过一般的APP性能优化措施,现在特别针对iOS开发,根据之前提到的所有优化方向,想要知道iOS开发者可以实施的具体步骤。 首先,我需要回顾之前的回答,确保覆盖所有提到的优化方向,比如启动速度、内存管理、UI渲染、网络请求、安装包体积、耗电量和架构设计等。同时,用户希望得到iOS特定的建议,所以需要将通用的优化措施转化为iOS平台的具体实现方法。 启动速度优化方面,iOS的启动过程分为pre-main和main之后两个阶段。对于pre-main阶段,需要减少动态库的数量,合并或者使用静态库。同时,检查+load方法的使用,尽可能将其替换为+initialize,或者在运行时延迟加载。使用Instrument的Time Profiler来检测启动时间,找出耗时操作,并将其延迟或异步执行。对于main之后的阶段,可以将非必要的初始化任务延迟到启动完成之后,或者放在后台线程执行。使用Xcode的MetricKit来监控启动时间,并结合优化启动故事板或启动图,减少根视图控制器的初始化时间。 内存管理方面,iOS可以使用Instruments的Allocations和Leaks工具来检测内存泄漏和循环引用。避免使用强引用的闭包,使用weak或unowned来打破循环。对于图片资源,使用UIGraphicsImageRenderer代替UIGraphicsBeginImageContext,因为前者更高效。同时,加载大图时使用Downsampling技术,避免内存峰值。利用NSCache和URLCache进行缓存管理,及时释放不需要的资源。在后台时,释放非必要的内存,响应AppDelegate的applicationDidEnterBackground通知,清理缓存和临时数据。 UI渲染方面,减少视图层级,使用UIKit的组件如UIStackView来简化布局。避免使用透明视图和离屏渲染,设置layer的shouldRasterize为YES,并合理使用cornerRadius和masksToBounds。在滚动列表如UITableView或UICollectionView时,复用cell,减少动态高度计算,预计算并缓存高度。使用预取API如UICollectionViewDataSourcePrefetching提前加载数据。对于复杂动画使用Core Animation而不是频繁的UIView动画,以减少CPU负担。此外,使用InstrumentCore Animation工具检测帧率,确保保持在60fps以上。 网络请求优化方面,使用URLSession的缓存策略,合理设置NSURLRequest的cachePolicy。利用HTTP/2的多路复用减少连接时间,压缩数据使用gzip。在弱网环境下,调整超时时间,优先加载关键数据,延迟非必要请求。使用后台任务处理网络请求,如BGTaskScheduler,合理管理后台网络活动。同时,合并多个请求,减少请求次数,使用Combine框架或第三方库如Alamofire的批量请求功能。 安装包体积方面,删除无用资源和代码,使用App Thinning技术,根据设备分发不同的资源。使用Asset Catalogs管理图片,并转换为WebP或HEIC格式以减少大小。启用Bitcode优化,进行代码剥离(Dead Code Stripping),使用Link Map分析无用类和方法。动态库尽量合并,减少动态库的数量。资源文件压缩,音频文件使用适当的格式和码率。 耗电量优化方面,减少后台活动,使用低功耗的API,如使用CLLocationManager的startMonitoringSignificantLocationChanges代替持续定位。延迟非紧急任务,使用BGProcessingTask在合适的时间执行。减少屏幕亮度变化和动画,合理使用定时器,使用CADisplayLink而不是NSTimer来同步屏幕刷新。监控能耗,使用Xcode的Energy Log工具分析耗电情况,优化高耗能操作。 架构设计方面,采用模块化设计,使用Swift Package Manager或CocoaPods管理组件,减少耦合。异步编程使用GCD、OperationQueue或Swift的async/await,避免阻塞主线程。预加载数据,在空闲时提前加载可能需要的资源,使用NSPersistentContainer进行Core Data的预加载。对于启动项,使用启动服务管理器,将初始化任务按优先级和依赖关系管理,延迟非关键任务。 持续优化方面,集成Xcode的Metrics Organizer监控性能指标,使用第三方APM工具如Firebase Performance Monitoring或New Relic进行实时监控。编写单元测试和UI测试,自动化性能回归测试,确保优化不会引入新的问题。灰度发布,通过TestFlight分阶段发布,收集用户反馈和性能数据,验证优化效果。 需要确保每个措施都具体到iOS开发的工具、API或最佳实践,避免泛泛而谈。同时,可能需要提及一些常见的第三方库或框架,如使用Kingfisher进行图片加载优化,但应以苹果官方推荐的方法为主。还要注意iOS版本兼容性,例如Swift Concurrency需要iOS 13+,BGTaskScheduler需要iOS 13+等,可能需要提供替代方案。 最后,组织这些措施时,按照之前的优化方向分类,每个类别下列出具体的iOS措施,并尽可能给出示例或工具的使用方法,这样用户能够清晰理解如何实施。</think>以下是针对iOS开发的具体性能优化措施,结合上述所有优化方向整理而成: --- ### **一、启动速度优化** 1. **减少pre-main时间** - **减少动态库数量**:合并动态库或改用静态库(检查`Linked Frameworks and Libraries`)。 - **优化`+load`方法**:将`+load`中的逻辑迁移到`+initialize`或用`dispatch_once`延迟加载。 - **二进制重排**:通过Clang插桩(Order File)优化函数加载顺序,减少Page Fault(需Xcode 13+)。 - **工具检测**:使用Xcode的`Link Map`文件分析符号体积,或通过`Instruments`的`Time Profiler`分析启动耗时。 2. **优化main阶段** - **异步初始化**:将非必要初始化(如日志、三方SDK)放到后台线程(如`DispatchQueue.global()`)。 - **延迟加载**:使用懒加载属性(`lazy var`)推迟对象创建,避免启动时集中初始化。 - **简化首屏UI**:减少`LaunchScreen.storyboard`复杂度,避免在`application(_:didFinishLaunchingWithOptions:)`中同步加载过多视图。 --- ### **二、内存管理优化** 1. **检测与修复内存泄漏** - **工具检测**:使用`Instruments`的`Leaks`和`Allocations`工具,或开启Xcode的`Memory Debugger`(Debug Navigator)。 - **循环引用处理**:对闭包使用`[weak self]`,避免强引用循环;对`delegate`使用`weak`属性。 2. **图片与资源优化** - **高效解码**:使用`UIGraphicsImageRenderer`替代`UIGraphicsBeginImageContext`,避免主线程解码大图。 - **Downsampling技术**:加载大图时通过`ImageIO`调整尺寸(示例代码): ```swift func downsample(imageAt url: URL, to size: CGSize) -> UIImage? { let sourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary guard let source = CGImageSourceCreateWithURL(url as CFURL, sourceOptions) else { return nil } let options: [CFString: Any] = [ kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height), kCGImageSourceCreateThumbnailFromImageAlways: true, kCGImageSourceCreateThumbnailWithTransform: true ] return CGImageSourceCreateThumbnailAtIndex(source, 0, options as CFDictionary).flatMap { UIImage(cgImage: $0) } } ``` - **缓存管理**:使用`NSCache`缓存频繁访问的数据(如网络图片),并监听`UIApplicationDidReceiveMemoryWarningNotification`自动清理。 3. **对象复用** - **Cell复用**:在`UITableView`/`UICollectionView`中严格复用Cell(`dequeueReusableCell`)。 - **池化技术**:对高频创建的对象(如数据库连接)实现对象池。 --- ### **三、UI渲染流畅度** 1. **减少主线程阻塞** - **异步布局**:复杂UI布局使用`DispatchQueue`异步计算,再回调主线程更新。 - **预计算布局**:对动态高度的Cell提前计算并缓存高度(如`UITableView`的`estimatedRowHeight`优化)。 2. **优化列表性能** - **预加载与预取**:对`UICollectionView`使用`UICollectionViewDataSourcePrefetching`提前加载数据。 - **避免离屏渲染**:减少`layer.cornerRadius` + `masksToBounds`组合,改用`CAShapeLayer`绘制圆角。 - **异步绘制**:自定义视图时,将`draw(_:)`中的复杂绘制逻辑放到后台线程,结果缓存为`UIImage`后显示。 3. **帧率监控与优化** - **检测工具**:通过`CADisplayLink`自定义帧率监控,或使用`Instruments`的`Core Animation`工具查看掉帧原因。 - **减少透明图层**:设置`opaque = true`避免混合叠加计算。 --- ### **四、网络请求优化** 1. **请求合并与缓存** - **HTTP缓存**:利用`URLCache`设置合理的缓存策略(如`NSURLRequest.UseProtocolCachePolicy`)。 - **批量请求**:合并多个接口请求(如使用`GraphQL`),减少网络往返次数。 2. **协议与数据优化** - **使用Protobuf**:替代JSON解析(需服务端配合),减少数据体积和序列化时间。 - **压缩数据**:请求头添加`Accept-Encoding: gzip`,启用服务器端压缩。 3. **弱网适配** - **超时与重试**:设置短超时(如5秒),失败后按指数退避策略重试。 - **优先级管理**:使用`URLSessionTask`的`priority`属性区分关键和非关键请求。 --- ### **五、安装包体积优化** 1. **资源精简** - **删除无用资源**:使用`Asset Catalog`管理图片,开启`On-Demand Resources`动态下载非必要资源。 - **图片压缩**:转换为WebP格式(需集成`SDWebImageWebPCoder`),或使用Xcode的`HEIC`导出选项。 2. **代码瘦身** - **死代码删除**:开启`Dead Code Stripping`(`DEAD_CODE_STRIPPING = YES`),并定期通过`AppCode`检测无用代码。 - **符号剥离**:设置`Strip Linked Product = YES`,`Symbols Hidden by Default = YES`。 3. **Bitcode与编译优化** - **启用Bitcode**:允许Apple进一步优化二进制文件(需所有依赖库支持)。 - **优化编译选项**:设置`Optimization Level`为`-Os`(兼顾速度和体积)。 --- ### **六、耗电量优化** 1. **后台任务管理** - **统一调度任务**:使用`BGTaskScheduler`(iOS 13+)处理后台刷新、清理等任务,替代频繁的`Timer`。 - **限制定位精度**:非导航类场景使用`kCLLocationAccuracyHundredMeters`替代高精度定位。 2. **减少CPU/GPU负载** - **暂停非必要动画**:在应用进入后台时停止`CADisplayLink`或`CAAnimation`。 - **降低刷新频率**:对非交互性UI(如静态页)设置`preferredFramesPerSecond = 30`。 --- ### **七、架构与工程化优化** 1. **模块化与组件化** - **使用Swift Package Manager**:解耦业务模块,减少编译依赖。 - **按需加载**:通过`@_spi`或条件编译控制非核心功能初始化。 2. **预加载与懒加载** - **数据预取**:在用户空闲时预加载下一页数据(如`UICollectionView`滑动至底部前触发加载)。 - **懒加载非关键服务**:如推送、统计SDK延迟到用户首次交互后初始化。 --- ### **八、持续监控与测试** 1. **集成APM工具** - **Xcode Metrics**:查看启动时间、内存、磁盘写入等指标。 - **第三方工具**:接入Firebase Performance Monitoring或New Relic监控卡顿、ANR。 2. **自动化测试** - **编写性能测试用例**:使用XCTest的`measure`方法统计关键路径耗时。 - **CI/CD集成**:通过Fastlane脚本在每次构建后输出性能报告。 --- ### **典型案例参考** - **冷启动优化**:字节跳动通过二进制重排技术减少Page Fault,提升启动速度。 - **微信图片加载**:采用Downsampling技术避免大图内存溢出。 - **淘宝列表流畅度**:UICollectionView预加载+异步解码图片。 通过结合工具链分析、代码级优化和架构设计,可系统性提升iOS应用性能
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值