当有人问:详情页的数据变了,列表页面的对应UI如何同步修改?

废话开篇:最近写了一段 ApiCloud 混合开发 APP,说是混合开发,但是大部分的功能还是以 JS 为主,其实,ApiCloud 跨平台的开发只能算是工具,而不能算是一门语言。那么,JS 本身是运行在 JS 环境中的,普通页面的 JS 运行在 WKWebView 对应的环境里。当然,也可以初始化一个 JS 运行环境,让一些自定义代码运行在这个脱离 webViewJS 运行环境里。但是,不管是以什么方式运行 JS,如果不在同一个环境下,那么,该环境下的 JS 数据在不借助桥接的情况下是不能共享的,所以,就会有人好奇,原生开发下,详情页的数据变了,列表页面的对应UI如何同步修改?

一、JS模式下,详情页的数据变了,列表页面的对应UI如何同步修改?

JS 的运行及访问界限被 WKWebView 限制住了,如果不通过原生的多 WebView 之间的通信辅助是无法做到数据共享的。

二、iOS模式下,为什么详情页的数据变了,列表页面的对应UI可以同步修改?

原生的所有的值、对象、方法,都在同一个运行环境里,如果指针传的足够远,那么,程序将会在任何地方访问或调用某些对象或方法。

三、iOS模式下,如何做到详情页的数据变了,列表页面的对应UI可以同步修改?

实现方法其实有很多种:

1、代理回执;

2、闭包回执;

3、通知回执;

4、对象观察者回执;

上面所有方法的思路,其实都是通过“一根线”链接“两个点”,只是实现的方式不一样而已。

上面最好的方式还是通过对象观察者进行回执修改,这个就好比大家在过斑马线,每个人都盯着信号灯,一旦绿灯亮起,那么,大家就动起来;反之,其他的方式就类似于,张三看见绿灯亮了,告诉李四,李四告诉王五…

四、iOS模式下,简单实现

3.1 实现效果

详情页的修改“点赞”数,上一级的列表“点赞”展示数也随之变化

屏幕录制2022-06-30 上午9.33.46.gif

3.2 实现思路

利用 RxSwift 观察者进行绑定

将对象的“点赞”属性分别绑定到 Cell 上面的 UILable 和详情页里的 UILable 上。那么,不管在个代码下修改了“点赞”属性值,那么,绑定的UI都会作出更改。

3.3 代码展示

这里说一下 RxSwift 使用过程中的注意点:

新闻对象类

  1. class NewsClass : NSObject, HandyJSON{
  2. @objc dynamic var thumb : Int = 0
  3. @objc dynamic var name : String?
  4. @objc dynamic var url : String?
  5. @objc dynamic var mineThumbStatus : Bool = false
  6. required override init(){
  7. }
  8. //绑定数据
  9. func rxBindContent(_ cell : WSLNewsListTableViewCell){
  10. self.rx.observeWeakly(Int.self, "thumb").asObservable().bind(to: cell.rx.thumbLab).disposed(by: cell.disposeBag)
  11. self.rx.observeWeakly(String.self, "name").asObservable().bind(to: cell.rx.nameLab).disposed(by: cell.disposeBag)
  12. self.rx.observeWeakly(String.self, "url").asObservable().bind(to: cell.rx.coverImg).disposed(by: cell.disposeBag)
  13. }
  14. }

注意点1:对象需继承 NSObject,以沿用 rx 系列的扩展方法。

注意点2:对于用 RxSwiftrx.observeWeakly 观察的对象属性需要用 @objc dynamic 修饰,赋予属性动态特性。

注意点3:在绑定数据方法里,利用 bind 方法将观察序列绑定在了自定义 cellrx 相关扩展下。

把赋值及其他相关的操作放在这里,外部进进行绑定

  1. //MARK: -扩展cell的rx属性
  2. extension Reactive where Base : WSLNewsListTableViewCell {
  3. var thumbLab : Binder<Int?> {
  4. return Binder(self.base){ cell ,content **in**
  5. cell.thumbLab.text = "点赞数:" + String(describing: content!)
  6. cell.thumbLab.sizeToFit()
  7. }
  8. }
  9. var nameLab : Binder<String?> {
  10. return Binder(self.base){ cell ,content in
  11. cell.nameLab.text = content!
  12. cell.nameLab.sizeToFit()
  13. }
  14. }
  15. var coverImg : Binder<String?> {
  16. return Binder(self.base) { cell , url in
  17. cell.coverImgView.kf.setImage(with: URL(string: url ?? ""))
  18. }
  19. }
  20. }

注意点4:这里的绑定方法是在 UITableViewDataSource 方法里,那么,重用机制自然会导致多次绑定。

cell 的绑定赋值操作
```swift - listView
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : WSLNewsListTableViewCell = tableView.dequeueReusableCell(withIdentifier: “CELL”, for: indexPath) as! WSLNewsListTableViewCell
//进行数据绑定
models?[indexPath.row].rxBindContent(cell)
//点击事件
cell.enterDetailBtn.rx.controlEvent(.touchUpInside).subscribe {[weak self] btn in
self?.pushDetailNewsVCSubject.onNext(self?.models?[indexPath.row])
}.disposed(by: cell.disposeBag)
return cell
}

  1. **model** 的绑定事件
  2. ```swift-class-mode
  3. func rxBindContent(_ cell : WSLNewsListTableViewCell){
  4. self.rx.observeWeakly(Int.self, "thumb").asObservable().bind(to: cell.rx.thumbLab).disposed(by: cell.disposeBag)
  5. self.rx.observeWeakly(String.self, "name").asObservable().bind(to: cell.rx.nameLab).disposed(by: cell.disposeBag)
  6. self.rx.observeWeakly(String.self, "url").asObservable().bind(to: cell.rx.coverImg).disposed(by: cell.disposeBag)
  7. }

解决复用机制重复绑定数据的办法就是绑定数据的序列销毁关联 cell.disposeBag,在 cellprepareForReuse 方法里进行 cell.disposeBag 的重置。

这里说一下 disposed 意义:意为销毁操作。在日常的开发中,会创建很多序列,但是,它们的生命周期交给谁处理呢?为了处理这个问题就出现了 disposed(by: disposeBag) 来辅助,把所有的序列关联到 disposeBag 上,那么,当 disposeBag 对象在某个时机被销毁的时候,同时销毁它关联的所有序列。

cell 复用前进行 disposeBag 重置

  1. override func prepareForReuse() {
  2. super.prepareForReuse()
  3. disposeBag = DisposeBag()
  4. }

这样就保证了,屏幕上可见的 cell 才具有绑定效果。

注意点5:在详情页修改传入参数的属性值。

  1. btn.rx.tap.subscribe {[weak self] _ in
  2. self?.newsClass?.thumb += 1
  3. }.disposed(by: disposeBag)

这样就完成了详情页修改属性,列表页面UI同步修改。

五、model 对象用 struct 类型的如何处理?

很遗憾,结构体属于值类型,在方法传入的时候会有一个副本。在逃逸闭包里,结构体更是会被复制出来,那么,如果不能操作原数据的话,扩展还有什么意义呢?

聪明的掘友会想到:是不是可以用 ReplaySubject 进行数据传递呢?因为 ReplaySubject 属于对象,即使结构体采用副本复制的方式传值,但是,对于对象类型的“属性”,复制的也是对象地址,那么,是不是可以进行直接 UI 绑定操作呢?答案是可以的! 但是这样的操作没有办法改变列表页的结构体数据,所以,不能进行数据同步,只能做到 UI 显示同步。

总结与思考:掘金大神很多,但是这篇小总结,显然不是给大神看的[抱拳][抱拳][抱拳]。但掘金里喜欢分享跟学习的小伙伴也很多,希望这篇小总结,对大家能起到帮助[抱拳][抱拳][抱拳]。


文章标签:

原文连接:https://juejin.cn/post/7114873458030280734

相关推荐

【论文阅读|深读】RDAA:Role Discovery-Guided Network Embedding Based on Autoencoder and A

ivx杨帆启航React/Pixi.js/FaaS、Krpano及微服务架构

支持SwiftUI!Swift版图片&视频浏览器-JFHeroBrowser上线啦

vivo官网APP全机型UI适配方案

《吐血整理》保姆级系列教程-玩转Fiddler抓包教程(7)-Fiddler状态面板-QuickExec命令行

SwiftUI 布局 —— 尺寸( 下 )

SpringBoot数据库管理 - 用Liquibase对数据库管理和迁移?

从SwiftUI的@State来看看Property Wrapper

七夕快到了,用SwiftUI做一个表达爱意的心形动画

RK3568开发笔记(四):在虚拟机上使用SDK编译制作uboot、kernel和buildroot镜像

【论文阅读|深读】GAS:Role-Oriented Graph Auto-encoder Guided by Structural Information

8个SwiftUI的小技巧让隔壁同事两眼放光,直呼太卷了

【摸鱼神器】UI库秒变低代码工具——表单篇(二)子控件

Phabricator Conduit API介绍

利用 UIScrollView 实现六棱柱图片浏览效果

【antd】5分钟快速完成antd样式的按需引入以及自定义主题

对话Robin Marx:HTTP\u002F3和QUIC将带来重大机遇和挑战

一种新的UI测试方法:视觉感知测试

【云原生 | 15】Docker commit与Docker build比较

VBA驱动SAP GUI完成界面元素值初始化