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

313 阅读2分钟

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

为什么选择RxSwift?

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

1. 按钮点击事件处理

✅ 传统实现(Target-Action)

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实现

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)

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实现

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. 网络请求链式调用

✅ 传统实现(回调嵌套)

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实现

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. 并发任务聚合

✅ 传统实现(串行请求)

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

✅ RxSwift实现

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(独立执行)

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(共享事件)

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

🔍 核心类解析

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

6. 错误处理与重试机制

✅ RxSwift实现

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状态管理

✅ 传统实现(直接赋值)

var isLoading = false {
    didSet {
        activityIndicator.isHidden = !isLoading
    }
}

✅ RxSwift实现

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单次结果网络请求