1.SwiftUI 是Apple 新出面向未来、跨多端解决方案、声明式编程
SwiftUI最新版本 2.0 但是需要 IOS 14 支持,多数现在还用的是IOS 13 所以很多不完善的东西都用SwiftUIX 以及各种库代替,bug也是层出不穷
2.下面是鄙人对 @State @Published @ObservedObject 理解,如有不对,还请指出
#1.@State 介绍
因为SwiftUI View 采用的是结构体,当创建想要更改属性的结构体方法时,我们需要添加mutating关键字:mutating func doSomeWork()例如。
然而,Swift不允许我们创建可变计算属性,这意味着我们不能编写mutating var body: some View——这是不允许的。
@State允许我们绕过结构体的限制:我们知道不能更改它们的属性,因为结构是固定的,但是@State允许SwiftUI将该值单独存储在可以修改的地方。
是的,这感觉有点像作弊,你可能想知道为什么我们不使用类-它们可以自由修改。但是相信我,这是值得的:随着你的进步,你会了解到SwiftUI经常破坏和重新创建你的结构体,所以保持它们的小而简单的结构对性能很重要。
提示:在SwiftUI中存储程序状态有几种方法,您将学习所有这些方法。@State是专门为存储在一个视图中的简单属性而设计的。因此,苹果建议我们向这些属性添加私有访问控制,
比如:@State private var tapCount = 0。
#2.@Published + @ObservedObject 介绍
@Published是SwiftUI最有用的包装之一,允许我们创建出能够被自动观察的对象属性,SwiftUI会自动监视这个属性,一旦发生了改变,会自动修改与该属性绑定的界面。
比如我们定义的数据结构Model,前提是 @Published 要在 ObservableObject 下使用
然后用 @ObservedObject 来引用这个对象,当然@State 不会报错,但是无法更新
class BaseModel: ObservableObject{
@Published var name:String = ""
struct ContentView: View{
@ObservedObject var baseModel:BaseModel = BaseModel()
var body: some View{
Text("用户名\(baseModel.name)")
Button(action: {
baseModel.name = "Renew"
}, label: {
Text("更新视图")
#3.最重要的部分 (代码注释部分最为主要,务必看完)
虽然上面案例运行中什么都正常展示加载,但是到了实际项目中,却一堆bug,这是如何导致的,如果对 这三种状态跟View绑定的关系不了解,很可能给自己留下隐患
#####1.先来看组案例
class WorkModel: ObservableObject {
@Published var name = "name"
@Published var count = 1
class UserModel: ObservableObject {
@Published var nickname = "nickname"
@Published var header = "http://www.baidu.com"
struct ContentView: View {
@ObservedObject var workModel:WorkModel = WorkModel()
@ObservedObject var userModel:UserModel = UserModel()
var body: some View {
VStack{
Text("work.count \(workModel.count)")
Text("work.name \(workModel.name)")
Text("user.nickname \(userModel.nickname)")
Text("user.header \(userModel.header)")
Button(action: {
userModel.nickname = "Renew"
userModel.header = "http://..."
workModel.name = "work name"
workModel.count += 1
}, label: {
Text("更新数据")
不出意外上面代码点击按钮就会更新数据,但是如果我们有个包装类呢
class WrapperModel: ObservableObject{
@ObservedObject var workModel:WorkModel = WorkModel()
@ObservedObject var userModel:UserModel = UserModel()
struct ContentView: View {
@ObservedObject var wrapperModel:WrapperModel = WrapperModel()
var body: some View {
VStack{
Text("work.count \(wrapperModel.workModel.count)")
Text("work.name \(wrapperModel.workModel.name)")
Text("user.nickname \(wrapperModel.userModel.nickname)")
Text("work.header \(wrapperModel.userModel.header)")
Button(action: {
wrapperModel.userModel.nickname = "Renew"
wrapperModel.userModel.header = "http://..."
wrapperModel.workModel.name = "work name"
wrapperModel.workModel.count += 1
}, label: {
Text("更新数据")
这时候点击按钮还会更新数据吗,答案是否定的,那这个是为啥呀???
因为SwiftUI更新数据的前提是触发
第一层 绑定的对象 wrapperModel下的属性(字段)发生更新才会调用视图层更新数据
但是 第一次下绑定的对象还绑定了 @ObservedObject 或者其他类型的对象呢?
还会触发第一次对象属性更新吗,答案是不能的
你可以在 didSet 事件里面捕捉,是捕捉不到的,所以视图是不会更新的,那这还有其他解决方案吗
有:
调用对象 wrapperModel.objectWillChange.send() 方法告诉View 层 我更新
但是这个就是绝对的了吗?:不是 如果层次再深一点的model 还是有bug,触发不了
#4.总结以及解决方案
class BaseobservableObject: ObservableObject {
@Published private var _lastUpdateTime: Date = Date()
public func notifyUpdate() {
_lastUpdateTime = Date()
#5.其他知识
class BaseModel: ObservableObject {
@Published var isLoading = false
class SonModel: BaseModel {
@Published var name = "name"
@Published var count = 1
struct ContentView: View {
@ObservedObject var sonModel:SonModel = SonModel()
var body: some View {
VStack{
Text("name \(sonModel.name)")
Button(action: {
sonModel.name = "Renew"
}, label: {
Text("加载")
1.SwiftUI 是Apple 新出面向未来、跨多端解决方案、声明式编程SwiftUI最新版本 2.0 但是需要 IOS 14 支持,多数现在还用的是IOS 13 所以很多不完善的东西都用SwiftUIX 以及各种库代替,bug也是层出不穷2.下面是鄙人对 @State @Published @ObservedObject 理解,如有不对,还请指出#1.@State 介绍因为SwiftUI View 采用的是结构体,当创建想要更改属性的结构体方法时,我们需要添加mutating关键字:mu.
修改List页面,增加收藏标记的属性,增加@State标注,这个标注Xcode的文档注释这样描述:
A linked View property that instantiates a persistent state
value of type Value, allowing the view to read and update it...
import SwiftUI
@propertyWrapper 属性包装,可以理解为装饰器模式,比如 @State,@Binding,@ObjectBinding,@EnvironmentObject
1 init(initialValue:),wrappedValue 和 projectedVal
对于这三个特性,我们可以简单记录一下,EnvironmentObject修饰属性是当前的环境变量,并在它自己以及它的子视图都可以直接使用,也可以叫做当前当前视图全局变量。下面我们看一个编辑学生姓名的例子:
先定义一个学生数据模型,如下:
class Student: ObservableObject {
@Published var name = ""
然后在写一个编辑框,编辑学生的姓名:
struct EditStudentView: View {
@Environment
一、SwiftUI 布局简介
在这个技术项目中,我们将探讨 SwiftUI 如何处理布局。有些事情已经解释过了,有些可能是你自己弄明白的,但更多的是你在这一点上想当然的事情,所以我希望一个详细的探索能真正为 SwiftUI 的工作方式提供一些启示。
在此过程中,您还将学习如何创建更高级的布局对齐,使用GeometryReader构建特殊效果,以及更多——我知道您会热衷于在自己的应用程序中部署的一些真正强大的功能。
继续使用单视图应用程序模板创建一个新的 iOS 项目,并将其命名为 layoutDageM