今年 WWDC 最重要的关注点是什么?Swift!Swift 5.0 ABI 达到稳定,Swift 5.1 达到 Module Stability,预示着 Swift 进入了成熟期。苹果也开始认真地吃本身的狗食了,咱们看到这届大会上推出了几个用 Swift 写的 iOS 框架,占篇幅最大的,无疑是 SwiftUI。为了这个框架写得6,苹果能够改语言,还不止一处。此次给你们介绍的是 Swift 5.1 在 协议上的改进:Opaque Result Type 不透明结果类型。这个特性加强了 Swift 泛型的能力,影响了 SwiftUI 的设计。面试
本文咱们先了解 Swift 5.1 的不透明返回类型的用途,而后再经过 Swift UI 上的应用,加深对它的理解。swift
先来看一段代码,它展示了原来协议能力上的缺陷:app
protocol Shape {}
struct Rectangle: Shape {}
struct Union<A: Shape, B: Shape>: Shape {
var a: Shape
var b: Shape
}
struct Transformed<S: Shape>: Shape {
var shape: S
}
protocol GameObject {
associatedtype ShapeType: Shape
var shape: ShapeType { get }
}
struct EightPointedStar: GameObject {
var shape: Union<Rectangle, Transformed<Rectangle>> {
return Union(a:Rectangle(), b:Transformed(shape: Rectangle()))
}
}
复制代码
缺陷有两方面:框架
上述代码是能够编译经过的,可是 EightPointedStar
的 Shape
返回类型又臭又长,被暴露了出去;若是换成 Shape
则编译不经过,缘由是 associatedtype ShapeType
要求必须指定具体的类型,而 Shape
不实现 Shape
自己。ide
假如 Shape
协议中含有 Self
或者 associatedtype
,没法做为函数的返回参数。这是 Swift 泛型系统长久以来的一个问题。函数
而本文介绍的 Swift 5.1 Opaque Result Type 特性,解决了上述问题,它为协议做为返回类型提供如下能力:ui
语法上隐藏具体类型,因此叫作不透明结果类型spa
强类型:类型参数不丢失操作系统
容许带有 Self
或者 associatedtype
的协议做为返回类型设计
在 Swift 5.1 中,将返回类型改为 some
+ 协议名称的形式:
struct EightPointedStar: GameObject {
var shape: some Shape {
return Union(a:Rectangle(), b:Transformed(shape: Rectangle()))
}
}
复制代码
这类的泛型特性也被称做“反向泛型”,由于具体的类型参数是由“实现部分”指定并隐藏起来的,而通常的泛型是由“调用者”所指定的。
上面这个例子中:语法上隐藏具体类型很明显,再举一个例子说明其它 2 个特性:
// 这个例子在Xcode 11 beta 2 以后能 work
func foo<T: Equatable>(_ x: T, _ y: T) -> some Equatable {
let condition = x == y
return condition ? 42 : 11
}
func test() {
let x = foo("apples", "bananas")
let y = foo("apples", "oranges")
print(x == y) // 这里能够被调用是由于泛型系统保留了强类型
}
复制代码
这个例子显示了不透明结果类型的三个特性:既对外隐藏了具体的 Equatable
类型;又保留了强类型(使得 x == y
)能够比较;还支持了 Equatable
这个带 Self
的泛型约束。
不透明结果类型对于函数实现有一个加强的要求:函数实现必须返回同一个具体类型,以上述代码为例:不能返回 Equatable
或者是 不一样类型的 Equatable
的实现。
这里还有一个小问题:既然 x
和 y
能够直接比较,那么它们能否直接赋值给 var i: Int
呢?答案是对于静态类型系统是不能够的,它保留了 some Equatable
的具体类型隐藏功能,可是若是使用动态类型判断 as? Int
,则能够转换成 Int
。
SwiftUI 中的视图类型的基本定义是一个协议 View
public protocol View : _View {
// body 属性的类型
associatedtype Body : View
// 惟一属性 body 的类型是另外一个具体类型 View
var body: Self.Body { get }
}
复制代码
SwiftUI 最大特色的是声明式以及高度可组合,View
的惟一属性 body
是另外一个知足 View
约束的具体 View
类型,咱们在这里看到了组合以及递归两个特性。下面来看一个具体的 View
类型 ContentView
:
struct ContentView : View {
var body: some View {
VStack {
Text("Hello World")
Text("Love & Peace")
}
}
}
复制代码
ContentView
使用了不透明结果类型的特性,对外隐藏了具体类型 VStack
。此外,ContentView
的具体类型都是经过它的 body
属性递归定义的(取决于它所包含的具体 View
):
全部的递归定义都须要一个终止条件,因而就有了如下这些原生 View
:Text
、Color
、Spacer
、Image
、Shape
、Divider
等
很高兴看到苹果终于开始提供 iOS 操做系统中的 Swift-Only 的 Framework,它对于 Swift 的推广和语言改进有进一步的促进做用。
另外,咱们也要注意到这个特性增长了 Swift ABI 的能力,须要最新的 runtime 才能运行。
扫描下方二维码,关注“面试官小健”