作者简介
梁启健,携程金融支付中心开发工程师,主要负责支付iOS端的开发与优化工作,喜欢研究大前端和跨平台技术。
SwiftUI是一种新颖的构建UI方式和全新的编码风格,本文以通俗易懂的语言,从Swift 5.1语法新特性和SwiftUI的优势方面进行分享,希望对热爱移动端的同学有一定的帮助,让大家尽可能快速、全面和透彻地理解SwiftUI。
一、背景
苹果于2019年度WWDC全球开发者大会上,发布了基于Swift建立的声明式框架--SwiftUI,其可以用于watchOS、tvOS、macOS等苹果旗下产品的应用开发,统一了苹果平台的UI框架。
正如官网所言Better apps. Less code:用更少的代码构建更好的应用。目前想要体验SwiftUI,需要以下的准备:Xcode 11 beta和macOS Mojave or Higher,如果想要体验实时预览和完整的Xcode 11功能,需要macOS 10.15 beta。
本文主要从以下三个方面讲述SwiftUI的特性:
从代码层面理解Swift 5.1新语法的底层实现;
从数据流方面阐述SwiftUI的黑魔法;
从布局原理层面阐述SwiftUI组件化的优势;
二、SwiftUI的特性
本节对Opaque Result Type, PropertyDelegate, FunctionBuilder三个语法新特性进行讲解,结合部分伪代码和数据流分析,由浅入深地理解,其在SwiftUI中的作用。
2.1 Opaque Result Type
新建一个SwiftUI的新项目,会出现如下代码:一个Text展示在body中。
struct ContentView : View {
var body: some View {
Text("Hello World")
}
}
对于some View的出现,大家可能会觉得很突兀。一般情况下,闭包中返回的类型应该是用来指定body的类型,如下代码所示,如果闭包中只有一个Text,那么body的类型应该就是Text。
struct ContentView : View {
var body: Text {
Text("Hello World")
}
}
然而,很多时候在UI布局中是确定不了闭包中的具体类型,有可能是Text、Button、List等,为了解决这一问题,就产生了Opaque Result Type。
其实View是SwiftUI一个核心的协议,代表了闭包中元素描述。如下代码所示,其是通过一个associatedtype修饰的,带有这种修饰的协议不能作为类型来使用,只能作为类型约束来使用。
通过Some View的修饰,其向编译器保证:每次闭包中返回的一定是一个确定,而且遵守View协议的类型,不要去关心到底是哪种类型。这样的设计,为开发者提供了一个灵活的开发模式,抹掉了具体的类型,不需要修改公共API来确定每次闭包的返回类型,也降低了代码书写难度。
public protocol View : _View {
associatedtype Body : View
var body: Self.Body { get }
}
2.2 PropertyDelegate
复杂的UI结构一直是前端布局的痛点,每次用户交互或者数据发生改变,都需要及时更新UI,否则会引起某些显示问题。但是,在SwiftUI里面,视图中声明的任何状态、内容和布局,源头一旦发生改变,会自动更新视图,因此,只需要一次布局。在属性前面加上@State关键词,即可实现每次数据改动,UI动态更新的效果。
@propertyDelegate public struct State<Value> :
DynamicViewProperty, BindingConvertible
上述代码中,一个@State关键词继承了DynamicViewProperty和BindingConvertible,BindingConvertible是对属性值的绑定,DynamicViewProperty是动态绑定了View和属性。
也就是说,声明一个属性时,SwiftUI会将当前属性的状态与对应视图的绑定,当属性的状态发生改变的时候,当前视图会销毁以前的状态并及时更新,下面具体分析一下这个过程。一般