前言

在学习SwiftUI所有的地方,视图元素都定义一个struct并实现View协议,该协议定义body变量返回View类型。

但是为什么,这里一直是指定的struct, 而不是class呢?

尝试使用class

如果你使用class 在SwiftUI中定义一个View,那么你将遇到一个编译器的错误

Protocol 'View' requirement '_makeView(view:inputs:)' cannot be satisfied by a non-final class ('ContentView') because it uses 'Self' in a non-parameter, non-result type position



错误的含义是,代码中使用了ContentView作为参数,如果ContentView有子类,那么将产生未定义的行为,必须限制ContentView没有子类,因此需要加上final修饰

上面的错误和这里类似:

https://stackoverflow.com/questions/40270118/protocol-requirement-cannot-be-satisfied-by-a-non-final-class-because-it-uses-s

加上final修饰之后,代码可以编译,运行之后直接崩溃:

SwiftUI/CustomView.swift:49: Fatal error: views must be value types (either a struct or an enum); ContentView is a class.
2022-02-23 15:41:34.418714+0800 SwiftClassUI[98636:8723744] SwiftUI/CustomView.swift:49: Fatal error: views must be value types (either a struct or an enum); ContentView is a class.



遇到断言错误,这个是SwiftUI限制只能使用struct或者枚举

为什么SwiftUI限制使用struct

经过搜索,大致有两个地方说明原因:

  • 一个是stackoverflow上说,因为SwiftUI中使用到了@State修饰状态,将和state和当前view进行绑定,如果是class,会遇到问题
  • 而是2019年的wwdc, swiftui_essentials, 其中有一个点提到了SwiftUI为什么采用struct而不是像UIKit一样的class

If you're coming from UIKit or AppKitt, you've probably gotten used to views being defined as classes that inherit from a common view superclass instead of as structs conforming to protocols.
For example, custom views in UIKit inherit from the UIView superclass.
And UIView defines storage for common view properties like alpha and backgroundColor.
Let's imagine we built our OrderHistory using UIKit instead of SwiftUI.
Our Custom View would inherit the stored properties of UIView as well as adding more properties for its own custom behavior.
So how is SwiftUI different than this? Well, remember that in SwiftUI we represent those same kinds of common view properties as separate modifiers instead, like we did for opacity and background.
And each of these modifiers creates their own view.
And this means that the storage for those properties is distributed across our view hierarchy in each of these modifier views instead of being inherited by every individual view.
Now this allows our views to be lighter weight, optimizing their storage for just their unique purpose.
And in this world, it makes a lot of sense that view just becomes a protocol because it's no longer needing to serve a common storage template for all of your views.
But what does this view protocol actually do? Well, let's remember our conceptual definition of a view.
Which is that a view defines a piece of our UI and we build bigger views by composing together smaller views.
And that's all that the view protocol does.
It defines a piece of our view hierarchy, giving it a name so that it can be composed and reused across your entire app.
And each concrete type of view is just an encapsulation of some other view representing its contents in its body property and all of the inputs required to create that view represented by its properties.
Now the actual protocol just defines that one body property returning just another kind of view.
But look

总结

  • struct相比class,能节省更多空间,有时候不需要继承父类中一些不需要的属性
  • struct相比class,操作更快,struct在栈上分配空间更加快
  • struct符合SwiftUI中的设计思路,界面是简单单一的,数据变化,UI就发生变化,数据不会在多处引用

为什么SwiftUI使用struct, 限制使用class的更多相关文章

  1. 从用SwiftUI搭建项目说起

    前言 后续这个SwiftUI分类的文章全部都是针对SwiftUI的日常学习和理解写的,自己利用Swift写的第二个项目也顺利上线后续的需求也不是特着急,最近正好有空就利用这段时间补一下自己对Swift ...

  2. [Android开发学iOS系列] iOS写UI的几种方式

    [Android开发学iOS系列] iOS写UI的几种方式 作为一个现代化的平台, iOS的发展也经历了好几个时代. 本文讲讲iOS写UI的几种主要方式和各自的特点. iOS写UI的方式 在iOS中写 ...

  3. SwiftUI 官方教程(八)

    8. 动态生成预览 接下来,我们会在 LandmarkList_Previews 中添加代码以在不同的设备尺寸上渲染列表.默认情况下,预览会以当前的 scheme 中设备的大小进行渲染.我们可以通过调 ...

  4. SwiftUI 官方教程(七)

    7. 给子 View 传递数据 LandmarkDetail 现在依然使用硬编码的数据来显示地标.像 LandmarkRow 一样,LandmarkDetail 类型和它组合的其他 view 都需要一 ...

  5. SwiftUI 官方教程(六)

    6. 在列表和详情之间设置导航 虽然列表已经能显示了,但是我们还不能通过点击单个地标来查看地标详情页面.SwiftUI教程 把 list 嵌入一个 NavigationView 中,并把每个 row  ...

  6. SwiftUI 官方教程(五)

    SwiftUI官方教程(五) 5. 同时使用 UIKit 和 SwiftUI 至此,我们已准备好创建 map view 了,接下来使用 MapKit 中的 MKMapView 类来渲染地图. 在 Sw ...

  7. SwiftUI 官方教程(四)

    SwiftUI 官方教程(四) 4. 自定义 Image View 搞定名称和位置 view 后,我们来给地标添加图片. 这不需要添加很多代码,只需要创建一个自定义 view,然后给图片加上遮罩.边框 ...

  8. SwiftUI 官方教程(三)

    3. 用 Stacks 组合 View 在上一节创建标题 view 后,我们来添加 text view,它用来显示地标的详细信息,比如公园的名称和所在的州. 在创建 SwiftUI view 时,我们 ...

  9. SwiftUI 官方教程(二)

    SwiftUI 官方教程(二) 2. 自定义 Text View 为了自定义 view 的显示,我们可以自己更改代码,或者使用 inspector 来帮助我们编写代码. 在构建 Landmarks 的 ...

  10. SwiftUI 官方教程(一)

    完整中文教程及代码请查看 https://github.com/WillieWangWei/SwiftUI-Tutorials   创建和组合 View 此部分将指引你构建一个发现和分享您喜爱地方的 ...

随机推荐

  1. Harbor高可用集群设计及部署(基于离线安装方式)

    原文转自:Harbor高可用集群设计及部署(基于离线安装方式) 架构至美 2022-09-05 09:28 发表于北京 编者荐语: 纯干货.实用,推荐系数5颗星. 以下文章来源于Harbor进阶实战  ...

  2. CentOS 6.3挂载读写NTFS分区(ntfs-3g) [亲测成功]

    CentOS 6.3挂载读写NTFS分区(ntfs-3g) CentOS不像Fedora,默认是没有自动挂载NTFS的,而它可以利用NTFS-3G来实现挂载及读写. NTFS-3G 是一个开源的软件, ...

  3. Launching Teamviewer remotely through SSH

    Launching Teamviewer remotely through SSH When you need to manage your Server remotely, but you can ...

  4. JS isPrototypeOf 和hasOwnProperty 还有in的区别

    isPrototypeOf 和hasOwnProperty 的区别 isPrototypeOf 是判断原生链上是否有该对象. 1.isPrototypeOf isPrototypeOf是用来判断指定对 ...

  5. python中的赋值、浅拷贝、深拷贝的区别

    赋值: 可变类型:赋值前后id不会变,赋值后的数据会随源数据变化: 不可变类型:赋值前后id不会变,赋值后的数据不会随源数据变化: 浅拷贝(copy): 可变类型:copy前后id会变,可变类型中存储 ...

  6. three.js实现数字孪生3D仓库一期(开源)

    大家好,本文使用three.js实现了3D仓库一期项目,给出了代码,分析了关键点,感谢大家~ 关键词:数字孪生.three.js.Web3D.WebGL.智慧仓库.开源 代码:Github 我正在承接 ...

  7. 02_Vue模板语法

    Vue模板语法有2大类:         1.插值语法:           功能:用于解析标签体内容.           写法:{{xxx}},xxx是js的表达式,且可以直接读取到data中的所 ...

  8. 第 8章 Python 爬虫框架 Scrapy(下)

    第 8章 Python 爬虫框架 Scrapy(下) 8.1 Scrapy 对接 Selenium 有一种反爬虫策略就是通过 JS 动态加载数据,应对这种策略的两种方法如下:  分析 Ajax 请求 ...

  9. Flink 最佳实践之使用 Canal 同步 MySQL 数据至 TiDB

    简介: 本文将介绍如何将 MySQL 中的数据,通过 Binlog + Canal 的形式导入到 Kafka 中,继而被 Flink 消费的案例. 一. 背景介绍 本文将介绍如何将 MySQL 中的数 ...

  10. [JDBC] Kettle on MaxCompute 使用指南

    简介: Kettle是一款开源的ETL工具,纯Java实现,可以在Windows.Unix和Linux上运行,提供图形化的操作界面,可以通过拖拽控件的方式,方便地定义数据传输的拓扑 .基本讲介绍基于K ...