swift - ResultBuilder

type
status
date
slug
summary
tags
category
icon
password
官方文档:
 

什么是 result builder?

Result builder 是一种声明属性,用来修饰类,结构体,枚举,利用它可以使 swift 实现嵌入领域特定语言 DSL (Domain Specific Language)。
DSL 没有计算和执行的概念,和命令式编程不同,使用的时候只需要声明规则,事实以及某些元素之间的层级和关系。我们使用 swift 和 UIKit 编写应用程序,一直以来都是命令式编程,直到 swiftUI 出现。
实际上我们已经多次接触过声明式语法,例如目前苹果推崇的 swiftUI 以及 cocopods 的 podfile 文件:
SwiftUI 的声明式语法就是通过 result builder 来实现的。如果我们查看 SwiftUI View 协议的声明,我们可以看到@ViewBuilder 属性定义的 body 变量:
ViewBuilder 就是使用 result builder 修饰之后实现的一个自定义构造器。
🎣
ResultBuilder 之前的名字是 functionbuilder,所以如果看到例如 @functionBuilder@_functionBuilder,本质是同一个东西。

自定义一个 result builder

从实践出发,我们可以自己尝试着实现一个简单的例子来学习。NSAttributedString 就是一个很好的例子,构建富文本是一件比较痛苦的事情,如果可以使用 swiftUI 的声明式语法,那不是很快乐?比如说像这样:
那让我们一步步来开始尝试使用 @resultBuilder

一、创建一个函数构造器

首先使用 @resultBuilder 属性标注一个结构体,然后我们必须要实现上面的这个方法,这个方法的含义是你想要如何通过 block 传递进来的数据构造 NSAttributedString。传递进来的是一个或者多个 NSAttributedString ,我们通过遍历拼接之后返回。 OK,我们已经完成了最重要的一步。

二、创建一个方便的初始化器

我们可以简单理解为AttributedStringBuilder结构体已经变成了一个简单的函数,使用的时候用 @AttributedStringBuilder 来修饰,在闭包中返回一个或者多个 NSAttributedString,生成一个拼接好的 NSAttributedString。 为了让我们使用起来更加的方便,我们给 NSAttributedStringstring 加上几个扩展方法,在使用字符串创建的时候更简洁。

三、大功告成

到这里已经全部完成了,让我们来试试我们的声明式富文本构造器。
notion image
以上其实已经实现了我们想要的效果,在其之上我们再扩展一些经常使用到的属性,就可以很方便的创建 NSAttributedString了,在 github 中的仓库就是使用的 @resultBuilder,其核心就是步骤一中的代码。
 
除此以外,@resultBuilder还有一些可选的实现方法,来完善构造器,例如我们如果返回一个可选值,该如何处理?如果想要像 swiftUI 一样支持 if-else,switch,该如何处理?
这些也很简单,在官方文档中,我们可以看到还有很多构建方法,用来解决不同类型,不同数据的处理:
这些方法分别对应内部不同的元素来构建的时候需要做的操作,构建器在转译时会自动选择对应的方法。

总结

以上,我们可以看到 resultBuilder 其实很简单,同时也非常强大,通过 resultBuilder 我们可以简化非常多的代码,甚至可以自己实现一个在 UIKit 框架下 swiftUI 式的声明式构建方式,具体该如何使用,取决于你的 idea💡。
 
想知道使用 result builder 可以干些什么有意思的事情吗?可以在下面这个仓库中看看。
awesome-result-builders
carson-katriUpdated Nov 24, 2023
 
这篇文章希望能让你对 ResultBuilder 有一定的了解,更深入的学习推荐肘子的文章:
ViewBuilder 研究(下) -- 从模仿中学习 | 肘子的Swift记事本
在 上篇 中,我们对 result builders 做了较详细的介绍。本篇我们将通过对 ViewBuilder 的仿制,探索更多有关 SwiftUI 视图背后的秘密。 本文中的视图是指符合 SwiftUI View 协议的各种类型 开发者通过 SwiftUI 框架提供的基础视图类型将自定义的视图串联起来,这些视图将向 SwiftUI 提供如下的信息: 开发者通过声明的方式对用户界面进行轻量级描述。 SwiftUI 会在恰当的时机从开发者创建的视图 body 属性中读取这些描述并进行绘制。 我们常说,视图是状态的函数。对于单个视图来说,它的状态是由所有与之相关的依赖共同组成的。视图的依赖包括:视图的基本属性(无需符合 DynamicProperty 协议)、可驱动视图更新的属性 ( 符合 DynamicProperty 协议,例如 @State、@Environment 等)以及 onRecevie 等元素。 SwiftUI 根据视图层次结构(视图树)中的视图类型和具体位置来区分视图(谁是谁)。对 SwiftUI 来说视图的类型本身就是最重要的信息之一。 与当前视图有关的一些轻量级代码。 SwiftUI 从加载视图、响应状态到屏幕绘制大概经历如下过程: 从根视图开始按视图层级结构沿特定分支(依据初始状态)逐个实例化视图,直到满足当前全部的显示所需 上述实例化后的视图值(结构值,非 body 值)将被保存在 SwiftUI 的托管数据池中 根据视图的依赖信息在 AttributeGraph
ViewBuilder 研究(下) -- 从模仿中学习 | 肘子的Swift记事本
 
附本篇文章中的Demo代码:
notion image
 
notion image
  • 📕 小红书/即刻:@轻舟
  • ☕ 如果我的内容有帮助到你,可以请我喝杯咖啡,这将鼓励我为你创造更多有价值的内容。
Buy Me A Coffee
  • Giscus

© 轻舟 2017-2024