swiftui和uikit的桥梁:UIViewRepresentable、Coordinator

大家好,我的开源项目PakePlus可以将网页/Vue/React项目打包为桌面/手机应用并且小于5M只需几分钟,官网地址:pakeplus.com

为什么说桥梁是UIViewRepresentable、Coordinator?

因为要想将UIKit的组件渲染到swift项目中,就需要转换的过程,比如有一个输入框,在swiftui中使用TextField来实现的,但是到UIKit中就需要使用UITextView实现,这个时候就需要使用UIViewRepresentable来协助你进行这个转换过程。

UIViewRepresentable这个协议是必须要实现两个函数

一个是makeUIView函数,用来初始化UITextView这个组件,只会执行一次,用来初始化等操作。

updateUIView是更新函数,SwiftUI 会比较视图层次,当发现MyView有变化的时候 ,自动调用其 updateUIView 方法来更新组件,其中传递的连个参数是uiView和context,_ 是外部参数,也就是参数标签,可以忽略不写,说是为了更加清晰,其实一坨垃圾。uiView就是makeUIView中最后返回的视图组件。context是上下文包含了访问协调器和环境信息等

这个时候再把组件放到swiftui中就可以展示出来了:

如果你的updateUIView函数中,什么内容都不放,那么当你在父组件中修改defaultText的值时候,子组件是不会发生改变的,因为你都没实现更新逻辑,怎么让页面改变?

在第一次加载时,makeUIViewupdateUIView 都会执行! 但是它们的执行顺序和次数不同:

arduino 复制代码
MyView init - text: 11        // 1. 初始化
makeCoordinator called        // 2. 创建协调器
makeUIView called - text: 11  // 3. 创建 UIView
updateUIView called - text: 11 // 4. 首次更新 ❗️

注意updateUIView 在第一次也会被调用!

SwiftUI 的渲染流程:

scss 复制代码
第一次渲染:
1. 创建 MyView 实例
2. 调用 makeCoordinator() 创建协调器
3. 调用 makeUIView() 创建 UIKit 视图
4. SwiftUI 将视图插入层级后,立即调用 updateUIView()
   → 确保视图状态完全同步

所以在makeUIView中你可以专注于写ui就好,初始化和更新逻辑就放在updateUIView中。

Coordinator又是干啥的?

Coordinator协调器是 UIViewRepresentableUIViewControllerRepresentable 中的核心概念,它在 SwiftUI 和 UIKit 之间充当桥梁和中介

如果没有这个玩意,你会发现,让你在UITextView中输入的内容改变后,你在父视图中再获取defaultText的值,是没有变为你输入的内容的!这就是数据没有反向绑定!!!!

但是如果你使用swiftui中的TextField组件,你就会发现它已经实现类数据的双向绑定。

Coordinator 协调器是一个自定义类,负责:

objectivec 复制代码
处理 UIKit 的委托(delegate)和数据源(data source)

管理 UIKit 视图的生命周期事件

在 SwiftUI 和 UIKit 之间传递数据和事件

也就是说,让数据发生变化时,也更新绑定的数据里面的值。

因为你在makeUIView中只是实现了UI,但是没有说这个UI组件当用户输入了内容后,怎么获取里面的值和做什么操作。这个时候,就需要使用 UITextViewDelegate 和 Coordinator 来做了。还有NSObject这个!

NSObject、UITextViewDelegate都是啥

什么是 NSObject?

kotlin 复制代码
// NSObject 是 Objective-C 运行时的基础类
// 在 Swift 中继承 NSObject 可以让 Swift 类获得 Objective-C 的能力
class Coordinator: NSObject {
    // 现在这个类可以:
    // 1. 使用 Objective-C 的运行时特性
    // 2. 作为代理(delegate)使用
    // 3. 使用 KVO(键值观察)
}

为什么需要 NSObject?
// ❌ 错误:纯 Swift 类不能作为 UIKit 的代理
class PureSwiftCoordinator: UITextViewDelegate {
    // 编译错误:UIKit 期望 Objective-C 兼容的对象
}

// ✅ 正确:继承 NSObject 后就可以作为代理
class Coordinator: NSObject, UITextViewDelegate {
    // 正常工作
}

NSObject 提供的能力:
class Coordinator: NSObject {
    // 1. Objective-C 运行时支持
    // 2. 内存管理(引用计数)
    // 3. 方法派发(动态派发)
    // 4. 序列化和反序列化支持
    // 5. KVO/KVC 支持
}

UITextViewDelegate 的作用

swift 复制代码
什么是 UITextViewDelegate?

// UITextViewDelegate 是一个协议(Protocol)
// 定义了 UITextView 可以调用的方法
protocol UITextViewDelegate: NSObjectProtocol {
    // 文本变化时调用
    optional func textViewDidChange(_ textView: UITextView)
    
    // 开始编辑时调用
    optional func textViewDidBeginEditing(_ textView: UITextView)
    
    // 结束编辑时调用  
    optional func textViewDidEndEditing(_ textView: UITextView)
    
    // 更多方法...
}


代理模式的工作原理:

// UIKit 的设计模式:
class UITextView: UIView {
    weak var delegate: UITextViewDelegate?  // 持有代理的弱引用
    
    func userDidTypeSomething() {
        // 当用户输入时...
        delegate?.textViewDidChange?(self)  // 通知代理
    }
}

// 我们的 Coordinator 实现代理:
class Coordinator: NSObject, UITextViewDelegate {
    func textViewDidChange(_ textView: UITextView) {
        print("用户输入了: \(textView.text)")
    }
}

为什么需要两者结合?

复制代码
// 1. Coordinator 继承 NSObject,获得 Objective-C 兼容性
class Coordinator: NSObject {  // ✅ 第一步:继承 NSObject
}
// 2. 遵守 UITextViewDelegate 协议,承诺实现某些方法

class Coordinator: NSObject, UITextViewDelegate {  // ✅ 第二步:遵守协议
func textViewDidChange(_ textView: UITextView) {
// 实现协议方法
}
}
// 3. 在 makeUIView 中设置代理
func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
textView.delegate = context.coordinator  // ✅ 第三步:设置代理
return textView
}

Coordinator又是干啥的?

Coordinator是协调器,用于继承 NSObject, UITextViewDelegate然后实现其中的方法,然后作为UITextView的代理,当UITextView文本内容发生变化后,就委托代理里面的方法,比如刚开始输入和已修改等操作函数。

设置代理的方法在makeUIView中实现:

如果你不实现这个UITextViewDelegate协议,就无法作为UITextView的代理,并报错:

在Coordinator中实现的textViewDidChange函数,然后在这个函数中实现数据的反向修改:

这样整个流程下来,就实现了数据的双向绑定
大家好,我是1024小神,技术群 / 私活群 / 股票群 或 交朋友 都可以私信我。 如果你觉得本文有用,一键三连 (点赞、评论、关注),就是对我最大的支持~

相关推荐
岁月宁静1 小时前
从 JavaScript 到 Python:前端工程师的完全转换指南
前端·javascript·python
特严赤傲1 小时前
在 Vue 中 v-for的写法对语法高亮的影响
前端·javascript·vue.js
PBitW1 小时前
从前端工程师的角度将SEO做到极致 -- 菜鸟来实操
前端·seo
雨雨雨雨雨别下啦2 小时前
【从0开始学前端】vue3路由,Pinia,组件通信
前端·vue.js·vue
调皮LE2 小时前
前端 HTML 转 PDF
前端
Nan_Shu_6142 小时前
熟悉RuoYi-Vue-Plus-前端 (1)
前端·javascript·vue.js
23124_802 小时前
网络管理-1
运维·服务器·前端
PBitW2 小时前
Electron 初体验
前端·electron·trae
D***M9762 小时前
WebSpoon9.0(KETTLE的WEB版本)编译 + tomcatdocker部署 + 远程调试教程
前端