Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SwiftUI的更新界面的原理 #187

Open
soapgu opened this issue Jan 29, 2023 · 0 comments
Open

SwiftUI的更新界面的原理 #187

soapgu opened this issue Jan 29, 2023 · 0 comments
Labels

Comments

@soapgu
Copy link
Owner

soapgu commented Jan 29, 2023

  • 前言

时间相对比较空闲。可以思考一些平时不注意又有一定深度的问题了。(其实就是空下来瞎想,又有时间去论证了)
引子:
是从邓兄的一个动画APP所引起的思考,一个细节引起了深思。原本只是想要改一个控件的颜色,改了State以后引起了整个空间的重新渲染。这点和我以前接触的程序,特别是MVVM的特性不太一样!
由此进一步提出两点疑问?

  • 什么情况下会重新渲染控件?
  • 数据改变呈现的过程是如何实现的?

从我学过的教程里面就没有讲过的。所有的知识都是“实现” “实现” “实现”

  • 不同系统对于数据决定呈现的解决方案

在开始深入SwiftUI这个框架之前。不妨先温故知新,从我现有的知识体系中去回顾下。比较一下区别可能意义更大一些

  1. Windows(WPF)
    WPF数据改变呈现是通过DataContext上下文传递数据,View是通过Binding关键字来建立联系的。
    其中DP(DependencyProperty)是实现的核心。DP可以把数据的变化反馈到控件上。
    控件也可以通过DP的回调函数来处理相关逻辑

  2. Andriod
    安卓的实现也是通过绑定,是用androidx.binding库实现的
    实现主要原理,不展开
    通过代码生成{ViewName}Binding接口和{ViewName}BindingImpl类

主要函数

  1. setVariable

设置数据函数

  1. onFieldChange

当我们调用notifyCallbacks会触发,设置内部变量mDirtyFlags,方便更新控件

  1. executeBindings

最最核心函数,处理绑定的初始化以及字段更新后处理控件更新的工作

  • 小小汇总

从上面两个系统中来看,虽然实现方式细节上有所差异,不过从大方向来讲是一致的

  1. 都有notifyPropertyChanged类似的函数
  2. 都有从数据字段到控件属性的桥梁传导机制
  3. 把MVVM框架展开,本质上就是数据变化,控件属性重新赋值的“低端”过程
  • SwiftUI的更新机制

主要SwiftUI没有直接讲更新机制的教程,只能先自己动手做实验
首先参考下How ScrollView lets us work with scrolling data这篇教程。
构建最小最简实验环境

  1. 需要自定义写一个控件,把关键日志埋进去
  2. 写一个@State变量并传给自定义控件
  3. 写一个控件去改变@State变量
import SwiftUI

struct CustomText: View {
    let text: String

    var body: some View {
        Text(text)
    }

    init(_ text: String) {
        print("Creating a new CustomText")
        self.text = text
    }
}

struct ContentView: View {
    
    @State private var text = "Binding,Please Change"
    
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundColor(.accentColor)
            TextField("Text",text: $text)
            CustomText("\(text)")
        }
        .padding()
    }
}

很快就有大致结论啦~~

图片

看日志节目,初来第一次显示时打印的"Creating a new CustomText"以外。 我每一次改变text这个@State变量都会打印"Creating a new CustomText"

最终我们得出来的结论和上两个系统的更新机制有一点不太一样

相同点

  1. 都有notifyPropertyChanged类似的函数
  2. 都有从数据字段到控件属性的桥梁传导机制

这里对于@State,我们可以认为是struct,对于@StateObject,属性用@published,某种意义上代替了“notifyPropertyChanged”

桥梁传导机制Swift可以做到代码直接声明,这点优势很明显。相对xaml和xml的Binding表达式的间接表达要“直白”得多

不同点
最关键的不同点。显然每次数据更新
控件都重新创建了!
控件都重新创建了!
控件都重新创建了!
虽然有一定的心理预期,但是看到运行结果,还是有一点颠覆认知的

  • SwiftUI更新机制的意义

还是有必要把这篇文章拿出来再看一遍!
Why does SwiftUI use structs for views?
性能上优势和专注设计界面是当初设计的考量

  1. struct是cheap的,class是expensive。性能上的优势,把struct设计成隐形眼镜一样的“抛弃型”,本身创建速度快,如果更新就新建,也确实省了“维护”的烦恼

  2. struct确实让代码要比class简单多了,更专注于设计

@soapgu soapgu added the Swift label Jan 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant