RxSwift实战:从传统开发到响应式编程的代码示例

这是一个RxSwift基本使用文章,具体的代码可以下载这个工程进行查看。RxSwiftLearn,示例代码来源于官方文档,自己只是在上边的学习项目中完善了一下代码,也可以直接去官网学习RxSwift中文文档

为什么选择RxSwift?

  1. 统一异步模型 :用Observable替代回调地狱
  2. 线程安全 :通过Scheduler明确线程调度
  3. 组合能力zip, flatMap等操作符灵活组合任务
  4. 生命周期管理DisposeBag自动清理资源
  5. 错误处理catchError, retry优雅处理异常

1. 按钮点击事件处理

✅ 传统实现(Target-Action)

swift 复制代码
override func viewDidLoad() {
    super.viewDidLoad()
    
    let btn = UIButton(type: .system)
    btn.setTitle("传统点击", for: .normal)
    btn.frame = CGRect(x: 50, y: 100, width: 120, height: 40)
    view.addSubview(btn)
    
    btn.addTarget(self, action: #selector(handleTap), for: .touchUpInside)
}

@objc func handleTap() {
    print("传统方式点击")
}

RxSwift实现

swift 复制代码
override func viewDidLoad() {
    super.viewDidLoad()
    
    let rxBtn = UIButton(type: .system)
    rxBtn.setTitle("Rx点击", for: .normal)
    rxBtn.backgroundColor = .systemBlue
    rxBtn.frame = CGRect(x: 50, y: 200, width: 120, height: 40)
    view.addSubview(rxBtn)
    
    rxBtn.rx.tap
        .subscribe(onNext: { [weak self] in
            print("响应式点击")
        })
        .disposed(by: disposeBag)
}

核心类解析

类名 作用 使用场景
rx.tap 扩展UIButton的点击事件流 替代addTarget
subscribe 订阅事件 处理点击逻辑
DisposeBag 管理资源释放 防止内存泄漏

2. 滚动视图事件监听

✅ 传统实现(UIScrollViewDelegate)

swift 复制代码
override func viewDidLoad() {
    super.viewDidLoad()
    
    let scrollView = UIScrollView()
    scrollView.frame = CGRect(x: 0, y: 300, width: 300, height: 200)
    scrollView.contentSize = CGSize(width: 300, height: 400)
    view.addSubview(scrollView)
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    print("传统滚动位置: $scrollView.contentOffset.x)")
}

✅ RxSwift实现

swift 复制代码
override func viewDidLoad() {
    super.viewDidLoad()
    
    let scrollView = UIScrollView()
    scrollView.frame = CGRect(x: 0, y: 300, width: 300, height: 200)
    scrollView.contentSize = CGSize(width: 300, height: 400)
    view.addSubview(scrollView)
    
    scrollView.rx.contentOffset
        .subscribe(onNext: { offset in
            print("响应式滚动位置: $offset.x)")
        })
        .disposed(by: disposeBag)
}

🔍 核心类解析

类名 作用 使用场景
rx.contentOffset 扩展UIScrollView的滚动事件流 替代scrollViewDidScroll
BehaviorSubject 保存最新偏移量 实时获取滚动位置

3. 网络请求链式调用

✅ 传统实现(回调嵌套)

swift 复制代码
override func viewDidLoad() {
    super.viewDidLoad()
    
    API.getToken { token in
        API.getUserInfo(token: token) { user in
            print("获取用户信息成功: $user.name)")
        } failure: { error in
            print("失败: $error)")
        }
    } failure: { error in
        print("失败: $error)")
    }
}

✅ RxSwift实现

swift 复制代码
override func viewDidLoad() {
    super.viewDidLoad()
    
    API.rx.getToken(username: "user", password: "123")
        .flatMapLatest { token in
            API.rx.getUserInfo(token: token)
        }
        .subscribe(
            onNext: { user in
                print("响应式获取用户: $user.name)")
            },
            onError: { error in
                print("响应式错误: $error)")
            }
        )
        .disposed(by: disposeBag)
}

核心类解析

类名 作用 使用场景
flatMapLatest 扁平化嵌套请求 实现请求链式调用
Single 单次结果封装 适配网络请求场景

4. 并发任务聚合

✅ 传统实现(串行请求)

swift 复制代码
override func viewDidLoad() {
    super.viewDidLoad()
    
    API.getTeacher(id: 1001) { teacher in
        API.getComments(id: 1001) { comments in
            print("教师: $teacher.name),评论数: $comments.count)")
        }
    }
}

✅ RxSwift实现

swift 复制代码
override func viewDidLoad() {
    super.viewDidLoad()
    
    Observable.zip(
        API.rx.getTeacher(id: 1001),
        API.rx.getComments(id: 1001)
    )
        .subscribe(
            onNext: { teacher, comments in
                print("教师: $teacher.name),评论数: $comments.count)")
            }
        )
        .disposed(by: disposeBag)
}

🔍 核心类解析

类名 作用 使用场景
zip 合并多个Observable 并发请求聚合
Tuple 存储组合结果 (Teacher, [Comment])类型

5. 冷热Observable对比

✅ 冷Observable(独立执行)

swift 复制代码
override func viewDidLoad() {
    super.viewDidLoad()
    
    let cold = Observable<Int>.create { observer in
        observer.onNext(1)
        return Disposables.create()
    }
    cold.subscribe { value in
        print("冷Observable: $value)")
    }
}

✅ 热Observable(共享事件)

swift 复制代码
override func viewDidLoad() {
    super.viewDidLoad()
    
    let hot = PublishSubject<Int>()
    hot.onNext(2)
    hot.subscribe { value in
        print("热Observable: $value)")
    }
}

🔍 核心类解析

类型 特点 使用场景
冷Observable 每次订阅独立执行 网络请求、一次性任务
热Observable 共享事件流 实时数据推送

6. 错误处理与重试机制

✅ RxSwift实现

swift 复制代码
override func viewDidLoad() {
    super.viewDidLoad()
    
    API.rx.login()
        .retry(3) // 最多重试3次
        .catchError { error in
            print("最终错误: $error)")
            return .just(User.default)
        }
        .subscribe { user in
            print("登录用户: $user.name)")
        }
        .disposed(by: disposeBag)
}

🔍 核心类解析

类名 作用 使用场景
retry 自动重试 网络不稳定时
catchError 错误降级 返回默认值避免崩溃

7. UI状态管理

✅ 传统实现(直接赋值)

swift 复制代码
var isLoading = false {
    didSet {
        activityIndicator.isHidden = !isLoading
    }
}

✅ RxSwift实现

swift 复制代码
let loadingState = BehaviorRelay<Bool>(value: false)
loadingState.asObservable()
    .subscribe { isLoad in
        activityIndicator.isHidden = !isLoad
    }
    .disposed(by: disposeBag)

🔍 核心类解析

类名 作用 使用场景
BehaviorRelay 可变状态容器 管理加载状态
asObservable() 转换为只读流 防止外部直接修改

所有核心类汇总表

类名 核心作用 典型使用场景
Observable 异步事件流 网络请求、用户交互
Observer 事件消费者 处理next/error/complete
Disposable 资源管理 取消订阅
Scheduler 线程调度 主线程更新
Operator 操作符 map, filter, zip
Subject 热Observable 实时事件广播
Relay 状态管理 BehaviorRelay, PublishRelay
Driver 安全绑定 UI绑定
Single 单次结果 网络请求
相关推荐
HouWan33 分钟前
SwiftUI 小技巧:如何读取 SwiftUI Font 的详细信息
ios·swiftui·apple
李游Leo1 小时前
HarmonyOS 7 实战开发 05:把页面做到可上线状态
ios·harmonyos
终端安全笔记6 小时前
描述文件、企业证书、MDM 不是三个名字,是三层
android·ios·智能手机
传奇开心果编程7 小时前
【SwiftUI入门练中学】第1课 从零开始
学习·ui·ios·swiftui·swift
丿Wayne12 小时前
iOS Token 刷新实战(Actor 避免并发重复刷新)
ios·swift·token·actor·swift并发
终端安全笔记1 天前
iOS 27 给了租赁一个新工具,但它只认受监督的设备
android·网络·安全·ios
大熊猫侯佩1 天前
独立 App 首发完成 iPhone Duo 展开态适配
ios·swiftui·swift
光影少年1 天前
setImmediate 和 setTimeout(0) 的区别
android·前端·react.js·ios·前端框架
2501_916008891 天前
SSE 和 gRPC 流式接口如何抓包,调试 SSE 与 gRPC 流式接口
网络协议·计算机网络·网络安全·ios·adb·https·udp
HouWan2 天前
Flutter: MediaQuery.of(context) 为什么可能拖慢页面?
android·flutter·ios