如何获取UIAlertController的Observable?自定义实现是否合理?(ReactiveCocoa/RxSwift)
关于响应式UIAlertController实现的问题解答
首先我会基于这类需求的主流实现逻辑来拆解你的问题——毕竟你提到只提供了部分代码,我先按常见的自定义响应式Alert实现来分析:
1. 你的实现是否正确?
这得看具体细节,但如果你的实现是**通过持有一个PublishSubject<Int>,在按钮点击时发送对应索引,最后返回subject.asObservable()**这种方式:
- 如果处理了生命周期:比如在UIAlertController被dismiss时调用
subject.onCompleted(),并且确保订阅dispose时能清理相关引用,那这个实现是基本正确的。 - 如果没处理生命周期:比如alert消失后没有发送completed信号,或者subject被alert或外部对象强持有,就会导致内存泄漏——观察者会一直持有subject,subject又持有alert相关对象,无法释放。
核心判断点就是:是否妥善处理了信号的终止和内存管理。
2. 不存储观察者的更优方案
当然有!最推荐的是使用Observable.create(RxSwift)或SignalProducer(ReactiveCocoa)的方式,完全不需要存储额外的Subject或观察者,把订阅、事件发送、清理逻辑都封装在创建闭包里:
举个RxSwift的实现例子:
extension UIAlertController { func rx_show(in viewController: UIViewController) -> Observable<Int> { return Observable.create { observer in // 给每个按钮绑定点击事件,发送对应索引 for (index, action) in self.actions.enumerated() { let originalHandler = action.handler action.handler = { _ in originalHandler?(action) observer.onNext(index) observer.onCompleted() // 点击后立即终止信号,避免内存泄漏 } } // 显示弹窗 viewController.present(self, animated: true) // 订阅销毁时的清理逻辑:如果弹窗还在显示就自动关闭 return Disposables.create { if self.presentingViewController != nil { self.dismiss(animated: true) } } } } }
这种方式的优势:
- 不需要持有任何Subject或观察者对象,所有逻辑都封装在create闭包内
- 订阅被销毁时自动清理弹窗,从根源避免内存泄漏
- 点击按钮后立即发送completed信号,保证信号生命周期和弹窗完全一致
ReactiveCocoa的类似实现可以用SignalProducer.init,在start方法里处理action的事件绑定和清理逻辑,思路和上面完全一致。
3. ReactiveCocoa或RxSwift中是否已有现成实现?
- RxSwift:官方RxCocoa没有直接封装UIAlertController的响应式实现,但社区有很多成熟的第三方库,比如
RxAlertController、RxSwiftCommunity/RxAlert,这些库已经帮你处理了内存管理、事件发送等所有细节,直接调用即可。你也可以参考这些库的实现,自己基于Observable.create封装轻量扩展。 - ReactiveCocoa:官方同样没有直接封装,但社区有类似的第三方库,或者可以通过
rac_signalForSelector绑定按钮点击事件,不过更优雅的方式还是用SignalProducer封装,和RxSwift的思路一致。部分老项目会用RACSubject实现,但还是推荐SignalProducer的方式更安全。
总结一下:如果你的现有实现处理了生命周期就是正确的;用Observable.create/SignalProducer的方式是不存储观察者的最优解;社区有现成的第三方库可以直接用,也可以自己基于create方法封装轻量扩展。
内容的提问来源于stack exchange,提问作者Ferran Maylinch
相关产品推荐
相关产品推荐

