【SwiftUI】1.特性之一:不透明返回类型

使用SwiftUI已经大半年了,对SwiftUI相关技术或多或少有一定地积累。很想把这些积累写成文章分享出来,也算对自己的一个输出。

而对于如何输入,最近我也一直在考虑。想来想去,就以一个系列的方式输出。对自己,能形成系统结构;对别人,也方便查找。

今天讲一讲不透明返回类型(Opaque Result Type)

先看现象

在我们写SwiftUI的时候,经常看到下面的代码

ContentView使用了一个View返回类型。

body的类型是some View。

这两个是什么含义呢?

这内容就是我们这次要分享的不透明返回类型。

分析

首先需要明白,这里View,非OC中的那个UIView,也非之前了解的视图的概念。在这里,它是一个新的概念--叫协议。

View是SwiftUI中一个最核心的协议,它表示屏幕上元素的描述,并且该协议含有一个associatedtype类型。

View协议的源码如下。

public protocol View : _View {        
    associatedtype Body : View        
    var body: Self.Body { get } 
}

这里申明了一个associatedtype类型的View。

associatedtype类型是什么概念呢?它是关联类型,类似于泛型(T)。作用是在传递参数或者返回值,不用固定某类型,而是可以比较宽泛的类型。相似于Any类型。

View协议在associatedtype基础上还有类型约束的作用。简单来说,它控制或者约束了参数或返回值的类型,不能随便输入或者不输入,需要遵循协议要求。

这也说明了它不是一个数据类型了,不能做类型来使用了。

如下用代码说明:

func createView(T:View)() -> T {

}

这种方式是正确的,带泛型来约束返回值类型。不是做返回类型。

 func ceateView() -> View {

 }

这种方式是错误的,指定了类型。

解释完了View的含义,再看看body返回some View是什么含义呢?它有什么好处呢?

首先body是SwiftUI界面的主体,类似一块画布。视图的控件都在这“画布”上挂载并显示。

然后就是返回some view的问题,这个答案就要回归SwiftUI的使用场景了,我们都知道SwiftUI包含一套UI控件工具类。它里面有很多的控件,如Text,Button,Image等等。我们在界面上都是使用这些控件组合成我们需要的界面。

我们先假设界面上就一个Text控件。

按Xcode项目,帮我们生成的代码如下:

struct ContentView : View {       
    var body: some View {             
        Text("Hello World")       
    } 
}

其实等价于如下的代码

struct ContentView : View {       
    var body: Text {            
        Text("Hello World")       
    } 
}

本质上, some View就是Text控件。

当界面上有很多控件的时候。例如,在登录界面,我们有一个logo图片,登录名标签,登录名输入框,密码标签,密码输入框和登录按钮。

是按下图的方式实现吗?

若按上图实现,是有问题的,返回了多个控件。返回的是Image,Text还是Button控件,不能明确。

按照SwiftUI的设计,应该统一返回一个类型。那怎么返回一个类型呢?这里就是加个VStack

struct ContentView: View {
    @State var userName = ""
    @State var password = ""
    var body: some View {        
        VStack {
            Image("logo.png")

            Text("用户名")
            TextField("UserName", text: $userName)

            Text("密码")
            TextField("password",text:$password)
            
            Button {
                print("")
            } label: {
                Text("登录按钮")
            }
        }
    }
}

统一封装到VStack中,最后返回类型是VStack了。虽然VStack里面有很多不同的控件,但最终是打包成VStack并以VStack返回。

在上述两个例子中,some view有时候是Text,有时候是VStack。这就是some的不透明性。

所有使用some View 来修饰,有以下好处:

1.每次返回的一定是一个确定、且遵守View协议的类型;

2.并不关心具体返回哪种类型。

这样的设计,为开发者提供了一个灵活的开发模式,抹掉了具体的类型,不需要修改公共API来确定每次闭包的返回类型。也降低了代码书写难度。

总结

Swft5.1版本新增加了 Opaque Result Type(不透明返回类型),更加方便了SwiftUI开发。

而不透明返回类型,本质上是,在SwiftUI开发过程中,很多控件组合一起显示界面时,每次统一返回的类型是一个确定的、且遵守View协议的类型,使开发者不用去关心到底是哪个控件的类型,反正是确定类型且遵守View协议。这样大大提高了开发效率。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
接着分析 (result (type_ident (component id='Bool' bind=Swift.(file).Bool))) (brace_stmt range=[re.swift:1:59 - line:14:1] (pattern_binding_decl range=[re.swift:2:5 - line:2:33] (pattern_named type='[UInt8]' 'b') Original init: (call_expr type='[UInt8]' location=re.swift:2:19 range=[re.swift:2:13 - line:2:33] nothrow (constructor_ref_call_expr type='(String.UTF8View) -> [UInt8]' location=re.swift:2:19 range=[re.swift:2:13 - line:2:19] nothrow (declref_expr implicit type='(Array<UInt8>.Type) -> (String.UTF8View) -> Array<UInt8>' location=re.swift:2:19 range=[re.swift:2:19 - line:2:19] decl=Swift.(file).Array extension.init(_:) [with (substitution_map generic_signature=<Element, S where Element == S.Element, S : Sequence> (substitution Element -> UInt8) (substitution S -> String.UTF8View))] function_ref=single) (argument_list implicit (argument (type_expr type='[UInt8].Type' location=re.swift:2:13 range=[re.swift:2:13 - line:2:19] typerepr='[UInt8]')) )) (argument_list (argument (member_ref_expr type='String.UTF8View' location=re.swift:2:29 range=[re.swift:2:21 - line:2:29] decl=Swift.(file).String extension.utf8 (declref_expr type='String' location=re.swift:2:21 range=[re.swift:2:21 - line:2:21] decl=re.(file).check(_:_:).encoded@re.swift:1:14 function_ref=unapplied))) )) Processed init: (call_expr type='[UInt8]' location=re.swift:2:19 range=[re.swift:2:13 - line:2:33] nothrow (constructor_ref_call_expr type='(String.UTF8View) -> [UInt8]' location=re.swift:2:19 range=[re.swift:2:13 - line:2:19] nothrow (declref_expr implicit type='(Array<UInt8>.Type) -> (String.UTF8View) -> Array<UInt8>' location=re.swift:2:19 range=[re.swift:2:19 - line:2:19] decl=Swift.(file).Array extension.init(_:) [with (substitution_map generic_signature=<Element, S where Element == S.Element, S : Sequence> (substitution Element -> UInt8) (substitution S -> String.UTF8View))] function_ref=single) (argument_list implicit (argument (type_expr type='[UInt8].Type' location=re.swift:2:13 range=[re.swift:2:13 - line:2:19] typerepr='[UInt8]')) )) (argument_list (argument (member_ref_expr type='String.UTF8View' location=re.swift:2:29 range=[re.swift:2:21 - line:2:29] decl=Swift.(file).String extension.utf8 (declref_expr type='String' location=re.swift:2:21 range=[re.swift:2:21 - line:2:21] decl=re.(file).check(_:_:).encoded@re.swift:1:14 function_ref=unapplied))) ))) (var_decl range=[re.swift:2:9 - line:2:9] "b" type='[UInt8]' interface type='[UInt8]' access=private readImpl=stored writeImpl=stored readWriteImpl=stored)
06-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员华仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值