关于 UIkit 和 SwiftUI 那些用法不同但最后实现相同的概念合集

引言

在之前,我有写过关于 iOS 入门开发的一系列合集:iOS 入门系列合集,这其中既有关于 UIkit 的描述,也有关于 SwiftUI的描述;但主要是围绕 SwiftUI 展开的,对于 UIkit 只是轻描淡写

然而,上项目之后,用的框架又是 UIkit,因此 SwiftUI 的知识被渐渐遗忘,突然有一天想要整理 UIkit 的学习路线,便回顾了一下 iOS 入门系列合集 的内容,在看到关于 SwiftUI 的数据状态和数据流部分时我有点懵了,一时间完全想不起来在 UIkit 中与之对应的实现是什么?因此本文便诞生了~

视图声明及布局

iOS 入门系列(二)这篇文章中有描述 UIkit 和 SwiftUI 在视图和布局上的不同的定义及实现方式

这里便再简要的总结一下:

  • 在视图声明上的区别
    • 使用的声明语法不同
    • SwiftUI 的语法更为简洁和直观
    • 视图属性设置不同:UIkit 需要通过属性或方法来设置,SwiftUI 直接通过链式调用的方式设置
  • 在布局上的区别
    • UIKit 需要使用容器视图(如UIViewUIStackView)以及约束来实现复杂的布局
    • SwiftUI 提供了VStackHStackZStack等更语义化的容器视图,以及内置的修饰符(如paddingspacing等),使得布局的定义更加简单

数据状态和数据流

iOS 入门系列(三) 一文中有对 SwiftUI 的数据状态和数据流的知识点进行介绍:通过属性包装器管理数据; 那么在 UIkit 中又是如何实现对于数据状态的管理的呢?

概念科普

UIkit 本身并没有提供专门的机制来直接管理应用程序的数据状态。UIkit 主要关注用户界面的创建、显示和交互,而数据状态通常由应用程序的数据模型 (Model) 或控制器 (Controller) 类来管理

UIkit 提供了一些工具,如:代理 (Delegate)、闭包 (Closure) 、通知中心 (NotificationCenter)、属性观察器等,用于在视图控制器、视图和模型之间传递数据和通知数据状态的变化,以达到同步更新视图的目的;同时,UIkit 也提供了关于视图重绘、重排的内置方法进行视图的更新

因此,在 UIkit 应用程序中,数据状态的管理是开发人员的责任,通常通过创建和维护数据模型或控制器类来实现。这些类会包含应用程序的数据逻辑,包括数据状态的管理和更新。代理、闭包和通知中心等工具可用于协助数据状态的传递和同步更新,但它们并不直接管理数据状态

可视化解析

上图分别画出了在 SwiftUI 和 UIkit 中如何对视图进行更新的系列操作,可以很明显看出 SwiftUI 采用属性包装器直接可以省略掉VC这一中间层,使视图的更新更简单直接;在 UIkit 中要实现视图与数据同步更新则需要借助VC这一中间层并配合代理通知中心闭包属性观察器来实现

拓展

代理、通知中心概念

关于代理可以参考 iOS 近期开发概念小结一文的delegate 就是一个属性? 部分的内容配合理解消化;

通知中心的使用相对简单,因为是全局的通知,所以只需要在发送通知的地方定义通知,然后在需要接收通知的地方注册并处理它即可,下面给出案例参考:

发送通知

swift 复制代码
import UIKit

// 定义通知名称
let myNotificationName = Notification.Name("MyCustomNotification")

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        // 发送通知
        NotificationCenter.default.post(name: myNotificationName, object: nil)
    }
}

接收通知

swift 复制代码
import UIKit

class AnotherViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        // 注册通知
        NotificationCenter.default.addObserver(self, selector: #selector(handleCustomNotification), name: myNotificationName, object: nil)
    }

    // 处理通知的方法
    @objc func handleCustomNotification() {
        print("Received custom notification")
    }

    deinit {
        // 当不再需要接收通知时,取消注册通知
        NotificationCenter.default.removeObserver(self, name: myNotificationName, object: nil)
    }
}

UIkit 视图重排、重绘

在上面已经提到过 UIkit 关于视图的重绘和重排的内置方法,这里就简略的小结一下它们的一些区别:

重绘和重排概念

  • 重绘:修改视图上的文本、图片等可见内容
    • 调用draw(_:)方法,可自定义
  • 重排:修改视图的位置、尺寸和布局属性
    • 调用layoutSubviews方法,可自定义
  • 简短总结:重绘性能消耗高于重排

UIkit 中重排的2种方法

  • setNeedsLayout():异步更新请求,不会立即触发布局,而是在当前运行循环结束后,系统会检查需要更新布局的视图,并在合适的时机执行layoutSubviews方法
  • layoutIfNeeded():用于强制立即执行布局的,不必等待系统的下一次布局更新

延伸概念

  • 系统会有多个事件循环,每个事件循环都处理不同类型的事件。UIKit 应用程序通常包括主 Run Loop 和任意数量的自定义 Run Loops
  • 主 Run Loop 是应用程序的主要事件循环,负责处理用户交互事件(如触摸事件、按钮点击等)以及其他系统事件
  • 自定义 Run Loops可以用于其他目的,例如:在后台执行任务
  • 每个 Run Loop 都有自己的循环周期,而且会不断运行,等待和处理事件。这有助于应用程序响应用户交互、网络请求、计时器事件等

setNeedsLayout方法通常用于告知系统在当前 Run Loop 结束时或下一个 Run Loop 中进行布局更新,以充分利用系统的事件循环来降低性能开销

小结

在 SwiftUI 中,通过属性包装器创建具有数据绑定的视图模型,在数据更改时,视图会自动更新以反映这些更改。这样的方法使得在 SwiftUI 中管理数据状态和更新视图更加直观和简化

在 UIkit 中,没有专门的机制来直接管理应用程序的数据状态。因此就需要借助Viewcontroller 层配合着代理通知中心闭包属性观察器来实现数据与视图的同步更新

相关推荐
Jinkey5 小时前
FlutterBasic - GetBuilder、Obx、GetX<Controller>、GetxController 有啥区别
android·flutter·ios
程序猿看视界11 小时前
如何在 UniApp 中实现 iOS 版本更新检测
ios·uniapp·版本更新
dr李四维15 小时前
iOS构建版本以及Hbuilder打iOS的ipa包全流程
前端·笔记·ios·产品运营·产品经理·xcode
️ 邪神15 小时前
【Android、IOS、Flutter、鸿蒙、ReactNative 】自定义View
flutter·ios·鸿蒙·reactnative·anroid
比格丽巴格丽抱1 天前
flutter项目苹果编译运行打包上线
flutter·ios
网络安全-老纪1 天前
iOS应用网络安全之HTTPS
web安全·ios·https
1024小神1 天前
tauri2.0版本开发苹果ios和安卓android应用,环境搭建和最后编译为apk
android·ios·tauri
lzhdim1 天前
iPhone 17 Air看点汇总:薄至6mm 刷新苹果轻薄纪录
ios·iphone
安和昂1 天前
【iOS】知乎日报第四周总结
ios
麦田里的守望者江1 天前
KMP 中的 expect 和 actual 声明
android·ios·kotlin