前言
在学习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修饰
加上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就发生变化,数据不会在多处引用