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 单次结果 网络请求
相关推荐
茶底世界之下3 小时前
花瓣要更柔和,还是更有反差?用 Awaking 做一次对比度取舍
ios
Anhty1 天前
2026最新免费手机音频处理工具 !!
android·功能测试·ios·智能手机·音视频
2501_915909061 天前
iOS应用从开发到上架App Store的完整发布流程与步骤指南
android·ios·小程序·https·uni-app·webview
初雪云1 天前
UniApp 云打包拿到 IPA 后,真正的发布工作才刚开始
ios·自动化·编辑器·产品经理·iphone
Lancker1 天前
没有 Mac 也能上架 iOS:GitHub Actions 全自动构建 + 签名 + TestFlight 送审实录
macos·ios·github
茶底世界之下1 天前
晚霞要多暖?用 Awaking 只改色温做一次取舍
ios
酒神dnspup1 天前
多地区网站可用性监控怎么做?DNSPup 从基线到告警的完整实战
运维·ios·云计算·iphone·dns·网络监控
福兮说2 天前
浏览器里把 iPhone 的 HEIC 转成 JPG:Chrome 解不开、转完大了七成、拍摄时间全丢,六个坑实测
前端·javascript·图像处理·chrome·ios·iphone·heic
茶底世界之下2 天前
时间线效果层,为什么不能只复用一个处理器?
ios·swift
ZZH_AI项目交付2 天前
实时字幕负责快,本地录音负责不丢:一个 iOS 录音功能为什么需要两条链路
ios·ai编程