专栏首页韦弦的偶尔分享为什么SwiftUI使用 some View 作为视图类型?

为什么SwiftUI使用 some View 作为视图类型?

SwiftUI非常依赖于Swift的一个叫做“不透明返回类型(opaque return types)”的强大特性,您每次编写some View时都可以看到它的实际作用。它意味着“一种符合View协议的特定类型,但我们不想说它到底是什么。”

返回some View与仅返回View相比有两个重要区别:

1、我们必须始终返回相同类型的视图。 2、即使我们不知道返回的视图类型,编译器也同样不知道。

第一个区别对于性能很重要:SwiftUI需要能够查看我们显示的视图并理解它们是如何变化的,这样它才能正确地更新用户界面。如果允许我们随机更改视图,那么对于SwiftUI来说,很难准确地找出更改的内容——它需要放弃一切,在每次小的更改之后重新开始。

第二个区别很重要,因为SwiftUI使用ModifiedContent构建数据的方式。之前我给你看了这段代码:

Button("Hello World") {
    print(type(of: self.body))
}
.frame(width: 200, height: 200)
.background(Color.red)

这将创建一个简单的按钮,然后使其打印其确切的Swift类型,并提供一些带有几个 ModifiedContent实例的长输出。

View协议有一个关联的类型附加到它之上,这是Swift说View本身并不意味着什么的方式,我们需要确切地说它是什么类型的视图。它实际上是容器,就像Swift不让我们说“这个变量是数组”一样,而是要求我们说数组中的内容:“这个变量是字符串数组。(个人理解:一个数组只能是[String]或者[Any]或者其他,但是不能是[],同理这里的View也是一样)

所以,它不允许写这样的视图:

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

但写这样的视图是完全合法的:

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

返回View是没有意义的,因为Swift想知道视图中的内容——它是一个必须填满的容器。另一方面,返回Text是可以的,因为我们已经填充了这个容器,Swift知道视图是什么。

现在让我们回到前面的代码:

Button("Hello World") {
    print(type(of: self.body))
}
.frame(width: 200, height: 200)
.background(Color.red)

如果我们想从我们的body属性中返回其中一个,我们应该写些什么?虽然您可以尝试找出修ModifiedContent泛型的确切组合,但这是非常痛苦的,而简单的事实是,我们不在乎:这都是SwiftUI内部的东西。

some View让我们做的是说“这将返回一种特定类型的视图,如ButtonText,但我不想说它到底什么。”因此,视图容器将由一个真实的视图填充,但我们不需要写出确切的类型。

想进一步吗?

现在,如果你好奇的话,你可能会想,SwiftUI是如何处理VStack这样的东西的——它符合View协议,但是“它填充了什么样的内容?”,“容器里面能装很多不同的东西?

好吧,如果您创建了一个包含两个文本视图的VStack,那么SwiftUI会无声地创建一个TupleView来包含这两个视图——一种特殊类型的视图,其中正好包含两个视图。所以,“VStack填充了什么样的视图?”回答:“这是一个包含两个文本视图的TupleView。”

如果VStack中有三个文本视图呢?然后是一个包含三个视图的TupleView。或者四种观点。或者八个视图,甚至十个视图——TupleView的一个版本可以跟踪十种不同的内容:

TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)>

这就是为什么SwiftUI在一个父级中不允许超过10个视图的原因:他们编写了TupleView的版本,可以处理2到10个视图,但不能超过10个(另一个版本:ForEach使用的)。

Previous: 为什么SwiftUI的修饰符顺序很重要?

Hacking with iOS: SwiftUI Edition

Next: 条件修饰符

赏我一个赞吧~~~

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • SwiftUI:使用 @EnvironmentObject 从环境中读取自定义值

    SwiftUI的环境使我们可以使用来自外部的值,这对于读取Core Data上下文或视图的展示模式等很有用。但是我们也可以将自定义对象发送到环境中,并在以后将它...

    韦弦zhy
  • Hacking with iOS: SwiftUI Edition 视图和修饰符项目——挑战

    这个技术项目旨在深入探究特定的SwiftUI主题,我希望您在这里学到了很多有关视图和修饰符的知识——为什么SwiftUI的视图使用结构体,为什么some Vie...

    韦弦zhy
  • SwiftUI:集成 MapKit

    自从2007年第一台设备问世以来,地图就一直是iPhone的核心功能,开发者几乎已经可以使用底层框架了。它叫做 MapKit,和UIKit一样,如果我们不介意进...

    韦弦zhy
  • MVC模式

    MVC代表ModelViewController(模型、视图、控制器 )模式。这种模式应用于应用程序的分层开发。

    祝你万事顺利
  • ASP.NET MVC4 View 指定视图

    这个控制器操作没有指定视图的名称。当不指定视图名称时,操作方法返回的 ViewResult 对象将按照约定来确定视图,它会在目录 /View/Controlle...

  • MySQL从删库到跑路_高级(三)——视图

    视图是由SELECT查询语句所定义的一个虚拟表,是查看数据的一种非常有效的方式。视图包含一系列带有名称的数据列和数据行,但视图中的数据并不真实存在于数据库中,视...

    良月柒
  • MySQL 视图

    看到这里,或许你已经对MySQL 的基本操作了如指掌,这篇文章讲解MySQL高级功能中 视图的概念及其用法。

    技能锦囊
  • MySQL 视图

    ​看到这里,或许你已经对MySQL 的基本操作了如指掌,这篇文章讲解MySQL高级功能中 视图的概念及其用法。

    技能锦囊
  • MySQL 视图

    数据库视图是虚拟表或逻辑表,它被定义为具有连接的SQL SELECT查询语句。 因为数据库视图与数据库表类似,它由行和列组成,因此可以根据数据库表查询数据。 大...

    房上的猫
  • 【asp.net core 系列】3 视图以及视图与控制器

    在之前的几篇中,我们大概介绍了如何创建一个asp.net core mvc项目以及http请求如何被路由转交给对应的执行单元。这一篇我们将介绍一下控制器与视图直...

    程序员小高

扫码关注云+社区

领取腾讯云代金券