iOS 开发中,异步渲染和异步绘制

在 iOS 开发中,异步渲染(Asynchronous Rendering)和异步绘制(Asynchronous Drawing)虽然有相似之处,但它们并不是完全相同的概念。

异步渲染(Asynchronous Rendering)

异步渲染主要指在后台线程进行与界面显示相关的耗时操作,比如图片加载、文本排版、数据处理等,然后在主线程更新 UI。这种做法的主要目的是避免阻塞主线程,以确保用户界面的流畅性和响应速度。

示例:

DispatchQueue.global(qos: .background).async {let processedImage = processImage(image)DispatchQueue.main.async {imageView.image = processedImage}
}

异步绘制(Asynchronous Drawing)

异步绘制则更专注于在后台线程进行实际的图形绘制操作,然后将绘制结果应用到 UI 上。这种做法不仅避免了主线程的阻塞,还能充分利用多线程的优势来提高图形绘制的效率和性能。

Core Graphics 和 Core Animation 是实现异步绘制的常用框架。例如,可以使用 CATiledLayer 来实现异步绘制大规模的图形。

示例:

class AsyncDrawingView: UIView {override class var layerClass: AnyClass {return CATiledLayer.self}override func draw(_ rect: CGRect) {let context = UIGraphicsGetCurrentContext()// 在此处执行绘制操作}
}let tiledLayer = AsyncDrawingView.layer as! CATiledLayer
tiledLayer.levelsOfDetail = 4
tiledLayer.levelsOfDetailBias = 3
tiledLayer.tileSize = CGSize(width: 256, height: 256)

区别与联系

  1. 目的和应用场景:

    • 异步渲染主要用于将数据处理、图片加载等操作放在后台线程执行,然后在主线程更新 UI,以提高界面的响应速度。
    • 异步绘制主要用于在后台线程执行实际的图形绘制操作,以提高图形绘制的效率和性能。
  2. 实现方式:

    • 异步渲染通常使用 GCD 或 OperationQueue 进行后台线程的任务分发。
    • 异步绘制通常使用 Core Graphics 或 Core Animation 等图形框架,并利用专门的图层(如 CATiledLayer)来进行后台绘制。

总结来说,异步渲染和异步绘制在概念和实现上有一些交叉,但它们的侧重点和应用场景有所不同。异步渲染更多地涉及数据处理和界面更新,而异步绘制则专注于高效的图形绘制操作。


拓展

facebook Texture 的实现原理是基于异步渲染还是异步绘制 ?还是两个都有用到 ?

Facebook 的 Texture(以前称为 AsyncDisplayKit)框架主要基于异步绘制(Asynchronous Drawing)来提高用户界面的性能和响应速度,同时也涉及异步渲染(Asynchronous Rendering)的一些方面。Texture 通过将耗时的界面绘制和布局操作放在后台线程中执行,来避免阻塞主线程,从而提供流畅的用户体验。

Texture 实现原理

异步绘制(Asynchronous Drawing)

Texture 的核心功能之一是异步绘制。它通过在后台线程进行实际的图形绘制操作,然后将绘制结果合成到主线程上显示。这一过程主要通过以下机制实现:

  1. ASDisplayNode:

    • ASDisplayNode 是 Texture 的基本单元,类似于 UIView,但它支持异步绘制。
    • ASDisplayNode 在后台线程执行 drawRect: 方法,通过 Core Graphics 进行绘制,并生成一个包含绘制内容的图像。
  2. 异步绘制队列:

    • Texture 使用专门的绘制队列来处理 ASDisplayNode 的绘制任务。绘制任务被分配到后台线程中执行,确保不会阻塞主线程。
  3. 绘制合成:

    • 绘制完成后,生成的图像被合成到主线程的视图层次结构中,确保界面更新的流畅性。
异步渲染(Asynchronous Rendering)

除了异步绘制,Texture 也利用了异步渲染的概念,将一些耗时的布局和数据处理操作放在后台线程中执行,然后在主线程更新 UI。

  1. 异步布局:

    • ASLayoutSpec 允许节点在后台线程进行布局计算。布局计算完成后,结果会被应用到主线程的界面中。
  2. 异步数据加载:

    • Texture 支持在后台线程加载数据,如图片和文本内容,然后将结果异步应用到 UI 组件上。

结合使用

Texture 的强大之处在于它同时结合了异步绘制和异步渲染,通过将界面绘制、布局和数据加载等操作放在后台线程中执行,大大提高了界面的响应速度和流畅性。

以下是一个使用 Texture 的示例:

import AsyncDisplayKitclass AsyncImageNode: ASDisplayNode {let imageNode = ASImageNode()override init() {super.init()addSubnode(imageNode)}override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {return ASInsetLayoutSpec(insets: .zero, child: imageNode)}func setImage(_ image: UIImage?) {imageNode.image = image}
}let asyncImageNode = AsyncImageNode()
DispatchQueue.global().async {let image = loadImageFromNetwork()DispatchQueue.main.async {asyncImageNode.setImage(image)}
}

总结来说,Facebook 的 Texture 框架通过结合异步绘制和异步渲染,提供了强大的性能优化能力,使得复杂的界面操作可以在后台线程中高效执行,从而保证主线程的流畅性和用户体验。


拓展 - 主线程操作UI的疑问

iOS 开发中 UI 相关的操作不是要求必须在主线程么 ?为什么 Texture 可以把界面元素的渲染和布局操作移到后台线程 ?

在 iOS 开发中,确实有一个重要的原则:所有 UI 相关的操作必须在主线程上执行。这是因为 UIKit 不是线程安全的,多线程操作 UI 可能会导致不可预见的行为和崩溃。然而,Texture 框架通过巧妙的设计和实现,将界面元素的渲染和布局操作移到后台线程,而不违反这一原则。

Texture 如何实现异步渲染和布局

  1. 异步计算布局:
    Texture 将布局计算移到后台线程。这些计算包括尺寸和位置的计算,而不是直接操作 UI。这意味着实际的 UI 更新还是在主线程上进行的,但计算工作已经在后台完成,从而减轻了主线程的负担。

    // Example of layout calculation in background thread
    [node measureWithSizeRange:ASSizeRangeMake(minSize, maxSize)];
    
  2. 异步绘制内容:
    Texture 将绘制操作也移到了后台线程。具体来说,绘制操作会生成一个图像或其他内容,然后这些内容会在主线程上应用到 UI 组件中。这样,虽然绘制在后台完成,但实际的 UI 更新还是在主线程上进行的。

    self.imageNode.imageModificationBlock = ^UIImage *(UIImage *image) {// Perform image modifications in background threadUIGraphicsBeginImageContextWithOptions(image.size, NO, [[UIScreen mainScreen] scale]);[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];UIImage *modifiedImage = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();return modifiedImage;
    };
    
  3. 双缓冲技术(Double Buffering):
    Texture 使用双缓冲技术来确保 UI 更新的线程安全。后台线程进行布局和绘制后,生成的内容会被传递给主线程,主线程只负责最终的 UI 更新。这种方法确保了 UI 操作在主线程上进行,同时最大限度地利用了后台线程的计算能力。

    [ASDisplayNode performBlockOnMainThread:^{// Apply the result of the background rendering to the UI[self.layer setContents:(__bridge id _Nullable)(image.CGImage)];
    }];
    
  4. 节点(Node)系统:
    Texture 的核心概念是节点(Node)系统,每个节点都是一个独立的实体,负责其自己的布局和渲染。节点的布局计算和绘制操作可以在后台线程中进行,而最终的 UI 更新还是在主线程上完成。

    ASDisplayNode *node = [[ASDisplayNode alloc] init];
    node.backgroundColor = [UIColor redColor];
    node.frame = CGRectMake(0, 0, 100, 100);
    

小结

Texture 通过将布局计算和绘制操作移到后台线程来提高性能,但它始终确保最终的 UI 更新在主线程上进行,从而遵守 iOS 的 UI 线程安全原则。通过这种方式,Texture 能够实现异步渲染和布局,从而提高应用的响应速度和性能,而不违反 UIKit 的线程安全要求。


拓展 - Texture 的异步绘制操作

Texture 将绘制操作移到后台线程,具体是怎么实现的 ?

Texture 框架通过几个关键机制将绘制操作移到后台线程,并确保这些操作最终在主线程上应用,以保持线程安全。以下是 Texture 实现异步绘制的具体步骤和原理:

1. 异步绘制任务分配

Texture 使用 ASDisplayNode 进行异步绘制任务的分配。每个 ASDisplayNode 都有一个 display 方法,该方法负责节点的绘制。Texture 会在后台线程中执行这个方法。

ASDisplayNode *node = [[ASDisplayNode alloc] init];
node.displayBlock = ^UIImage * {// 这是在后台线程中执行的绘制操作UIGraphicsBeginImageContextWithOptions(size, NO, 0);CGContextRef context = UIGraphicsGetCurrentContext();// 在 context 上执行绘制操作// ...UIImage *image = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();return image;
};

2. 使用异步绘制队列

Texture 维护了一个全局的异步绘制队列 ASDisplayQueue,它负责管理所有节点的异步绘制任务。每个绘制任务都会被放到这个队列中执行。

ASDisplayQueue *displayQueue = [ASDisplayQueue sharedDisplayQueue];
[displayQueue addDisplayBlock:^{// 执行节点的 displayBlockUIImage *image = node.displayBlock();// 在主线程上应用绘制结果dispatch_async(dispatch_get_main_queue(), ^{node.contents = (id)image.CGImage;});
}];

3. 双缓冲机制

为了确保主线程的 UI 更新是线程安全的,Texture 使用了双缓冲机制。在后台线程完成绘制操作后,绘制的结果(通常是 UIImage)会被缓冲,然后在主线程上应用到相应的 CALayer。

- (void)displayAsync:(BOOL)asynchronously {if (asynchronously) {dispatch_async(_asyncDisplayQueue, ^{UIImage *image = [self displayBlock]();dispatch_async(dispatch_get_main_queue(), ^{self.layer.contents = (id)image.CGImage;});});} else {UIImage *image = [self displayBlock]();self.layer.contents = (id)image.CGImage;}
}

4. 高效的图层绘制

Texture 使用 CATiledLayer 来处理大规模图形的异步绘制。CATiledLayer 会将图形分成若干小块,每块都可以在后台线程中独立绘制。这种方式不仅提高了绘制效率,还减少了内存占用。

CATiledLayer *tiledLayer = [CATiledLayer layer];
tiledLayer.tileSize = CGSizeMake(256, 256);
tiledLayer.levelsOfDetail = 4;
tiledLayer.levelsOfDetailBias = 3;

5. 异步图像加载

Texture 提供了 ASNetworkImageNode 来异步加载和显示网络图像。图像下载和处理在后台线程中进行,完成后在主线程上更新 UI。

ASNetworkImageNode *imageNode = [[ASNetworkImageNode alloc] init];
imageNode.URL = [NSURL URLWithString:@"https://example.com/image.jpg"];

小结

Texture 框架通过将绘制操作分配到后台线程执行,并使用双缓冲机制和 CATiledLayer 等技术,确保异步绘制的结果能够安全、高效地应用到主线程的 UI 上。这些技术使得 Texture 能够提供高性能的异步渲染和绘制能力,同时保持 UIKit 的线程安全原则。


拓展 - 具体用到的框架

Texture 将绘制操作分配到后台线程执行,使用的是 Core Graphics 还是 Core Animation ?

Texture 框架主要使用 Core Graphics 和 Core Animation 来实现异步绘制操作。以下是它们在 Texture 中的具体应用方式:

Core Graphics

Core Graphics 是一个强大的二维图形绘制框架,Texture 使用 Core Graphics 来处理后台线程中的绘制操作。这包括生成图像、绘制文本、绘制图形等。Core Graphics 允许在后台线程中执行这些绘制操作,然后将生成的图像应用到 UI 上。

示例:异步绘制图像
ASDisplayNode *node = [[ASDisplayNode alloc] init];
node.displayBlock = ^UIImage * {// 在后台线程中执行绘制操作CGSize size = CGSizeMake(100, 100);UIGraphicsBeginImageContextWithOptions(size, NO, 0);CGContextRef context = UIGraphicsGetCurrentContext();// 使用 Core Graphics 绘制内容CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);CGContextFillRect(context, CGRectMake(0, 0, 100, 100));UIImage *image = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();return image;
};

在这个例子中,displayBlock 在后台线程中执行,使用 Core Graphics 在 UIGraphicsGetCurrentContext() 上进行绘制操作。生成的 UIImage 最终会在主线程上应用到节点的内容中。

Core Animation

Core Animation 是一个强大的动画和图层绘制框架,Texture 使用 Core Animation 来管理和优化图层的显示,特别是在处理大规模图形和复杂动画时。CATiledLayer 是 Core Animation 中一个重要的类,Texture 使用它来实现异步绘制大规模图形。

示例:使用 CATiledLayer 实现异步绘制
class AsyncDrawingView: UIView {override class var layerClass: AnyClass {return CATiledLayer.self}override func draw(_ rect: CGRect) {let context = UIGraphicsGetCurrentContext()// 在此处执行绘制操作CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor);CGContextFillRect(context, rect);}
}let tiledLayer = AsyncDrawingView.layer as! CATiledLayer
tiledLayer.levelsOfDetail = 4
tiledLayer.levelsOfDetailBias = 3
tiledLayer.tileSize = CGSize(width: 256, height: 256)

在这个例子中,CATiledLayer 将视图的内容分成多个小块,并在后台线程中独立绘制这些小块。这种方式不仅提高了绘制效率,还减少了内存占用。

Texture 的异步绘制流程

  1. 定义节点和绘制块:
    每个 ASDisplayNode 可以定义一个 displayBlock,该块在后台线程中执行,使用 Core Graphics 进行绘制操作。

  2. 后台线程绘制:
    Texture 使用 ASDisplayQueue 将绘制任务分配到后台线程执行。在这些任务中,使用 Core Graphics 进行实际的绘制操作。

  3. 主线程应用绘制结果:
    在后台线程完成绘制操作后,生成的 UIImage 或其他内容会被传递到主线程,并应用到节点的 CALayer 中。

  4. 使用 CATiledLayer 优化大规模绘制:
    对于需要处理大规模图形的场景,Texture 使用 CATiledLayer 将绘制任务分成小块,并在后台线程中并行绘制这些小块。

小结

Texture 框架在实现异步绘制时,主要使用 Core Graphics 来处理后台线程中的绘制操作,并结合 Core Animation(特别是 CATiledLayer)来优化图层显示和管理。这种结合使得 Texture 能够提供高性能的异步渲染和绘制能力,同时保持 UIKit 的线程安全原则。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.tpcf.cn/pingmian/44207.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【SVN的使用- SVN的基本命令-SVN命令简写-注意事项-解决冲突 Objective-C语言】

一、SVN的更新命令:update 1.服务器如果新建了一个文件夹,yuanxing,版本变成6了, 我现在本地还只有三个文件夹,版本5, 终端里边,我们敲一个svn update, 我这儿就多了一个yuanxing文件夹, 这个就是更新,就是把服务器最新的代码下载下来, 假设服务器上大家提交了这…

react VS vue

什么是react 用于构建用户界面的js库 什么是vue 用于构建用户界面的渐进式js库 react是基于mvvm设计还是mvc设计 1、react是基于mvc设计的,但也不是完整的mvc模式 2、react把自己定义为view 3、组件逻辑定义为Controller层 4、虽然react不是完整的mvc模式&a…

KNIME 5.2.5 版本界面切换

1、安装完KNIME后,点击“Create workflow in your local space.” 2、发现是这个样子 4、进行切换。点击“menu”,最后点击“Switch to classic user interfaceto” 5、最终显示结果:

补光灯LED照明 2.7V4.2V5V升60V80V100V升压恒流芯片IC-H6902B

H6902B升压恒流芯片IC确实是一款为LED照明应用设计的稳定且可靠的解决方案。这款芯片具有以下几个显著特点: 高效率:效率高达95%以上,这意味着在驱动LED灯时,电源到LED的能量转换效率非常高,减少了能量损失&#xff0…

代码随想录算法训练营:30/60

非科班学习算法day30 | LeetCode452:用最少数量的箭引爆气球 ,Leetcode435:无重叠区间 ,Leetcode763:划分字母区间 介绍 包含LC的两道题目,还有相应概念的补充。 相关图解和更多版本: 代码随想录 (programmercarl.com)https:/…

centos磁盘空间满了-问题解决

报错问题解释: CentOS系统在运行过程中可能会出现磁盘空间不足的错误。这通常发生在以下几种情况: 系统日志文件或临时文件过大导致磁盘空间不足。 安装了大量软件或文件而没有清理无用文件。 有可能是某个进程占用了大量磁盘空间。 问题解决方法&a…

多服务下,服务与服务之间的调用(SpringCloudAlibaba入门一)

多服务下,服务与服务之间的调用(SpringCloudAlibaba入门一) 说明直接看代码 说明 在SpringBoot情况下,如果我们有多个子模块而且代码之间没有相互引用,那么子项目与子项目之间的调用方式就只能通过http请求的方式去调用…

必看!微信小程序必备证书!

微信小程序必备SSL证书。在日益增长的数字经济中,微信小程序已成为商家与消费者之间重要的交互平台。由于其便捷性和广泛的用户基础,越来越多的企业选择通过小程序来提供服务。然而,在开发和部署微信小程序时,确保数据安全是一个不…

Ubuntu22.04.4 LTS系统/安装Anaconda【GPU版】

安装过程 1.wget命令行下载 下载Anaconda并保存文件至本地指定目录 wget -c https://repo.anaconda.com/archive/Anaconda3-2023.09-0-Linux-x86_64.sh -P ~/Downloads/anaconda3 查看是否下载好了 2.安装Anaconda 2.1 bash命令安装 bash后面是anaconda3下载好的路径 bash …

学生选课管理系统(Java+MySQL)

技术栈 Java: 用于实现系统的核心业务逻辑。MySQL: 作为关系型数据库,用于存储系统中的数据。JDBC: 用于Java程序与MySQL数据库之间的连接和交互。Swing GUI: 用于创建图形用户界面,提升用户体验。 系统功能 我们的学生选课管理系统主要针对学生和管理…

AIGC 与软件开发:是助力还是取代?

《AIGC 与软件开发:是助力还是取代?》 在当今的软件开发领域,生成式人工智能(AIGC)的崛起无疑是一场变革性的浪潮。从代码生成到错误检测,再到自动化测试,AI 工具正以前所未有的方式融入开发者…

vue3源码(六)渲染原理-runtime-core

1.依赖关系 runtime-dom 依赖于runtime-core,runtime-core 依赖于reactivity和sharedruntime-core提供跨平台的渲染方法createRenderer,用户可以自己传递节点渲染的渲染方法renderOptions,本身不关心用户使用什么APIruntime-dom提供了为浏览器而生的渲染…

MSI打包后门成安装包

目录 浏览器下载地址 启动>next 选择后门所在路径,和生成安装包后存放路径 next>Hidden 配置变量 Look up随便找个伪装,然后点击一下Creat New ​注册表Registry导入 ​点击否,不购买专业版 ​安装包生成成功​编辑 浏览器下…

Mybatis进阶の常用配置级联查询

2 Mybatis常用配置 mybatis-config.xml中除了可以配置数据库服务器的环境以外,还可以配置其他的操作,帮助开发人员简化配置代码。常见的配置信息有以下内容: 1 配置内容 SqlMapConfig.xml中配置的内容和顺序如下:properties&am…

(自用)共享单车服务器(一):服务器项目配置

项目目录结构 conf:用来存放配置文件 git:用来存放从git上克隆的项目 src:用来存放项目源文件 test:用来存放测试文件 third:用来存放第三方头文件、第三方库 安装iniparser(关于iniparser的使用需进一步学习) 1.项目目录中创建git文件夹,用于存放GitHub上克隆…

计算机网络-IGMPv1工作原理简介

一、IGMPv1的原理简介 前面我们大致了解了IGMP用于在连接组播组成员的组播路由器总通过交互IGMP报文生成IGMP组表项和IGMP路由表项。IGMP报文封装在IP报文中。到目前为止,IGMP有三个版本:IGMPv1、IGMPv2、IGMPv3。 今天主要学习IGMPv1的作用和工作原理。…

深度学习论文: LLaMA: Open and Efficient Foundation Language Models

深度学习论文: LLaMA: Open and Efficient Foundation Language Models LLaMA: Open and Efficient Foundation Language Models PDF:https://arxiv.org/pdf/2302.13971.pdf PyTorch: https://github.com/shanglianlm0525/PyTorch-Networks 1 概述 本文介绍了LLaMA&#xff0…

浅谈重要组件JSR223介绍

浅谈重要组件JSR223介绍 JSR223 脚本组件是一个极其强大的特性,它允许用户利用各种脚本语言编写复杂的测试逻辑,极大地增强了 JMeter 的灵活性和功能。本文将对 JSR223 进行详细介绍,并解释如何在 JMeter 测试计划中有效地应用它。 JSR223 …

数据开源 | Magic Data大模型高质量十万轮对话数据集

能够自然的与人类进行聊天交谈,是现今的大语言模型 (LLM) 区别于传统语言模型的重要能力之一,近日OpenAI推出的GPT-4o给我们展示了这样的可能性。 对话于人类来说是与生俱来的,但构建具备对话能力的大模型是一项不小的挑战,收集高…

基于Android平台开发,仿头条新闻app

1. 项目模块功能思维导图 2. 项目涉及到的技术点 数据来源:聚合数据API使用okhttp网络请求框架获取api数据使用gson库解析json数据使用RecyclerViewadapter实现新闻列表使用SQLite数据库实现用户登录,注册,浏览历史记录使用SharedPreference…