RxSwift中map转subscribe出现意外nil值问题咨询
关于RxSwift中非可选类型变可选的问题解答
嗨,我来帮你把这个问题理清楚~你遇到的现象主要是Swift的类型推断机制和RxSwift的特性共同导致的,咱们逐个拆解来看:
第一个代码片段的问题解析
let tapEvent: ControlEvent<UITapGestureRecognizer> = chargingView.rx.tapGesture() tapEvent.map { _ in return CGPoint() }.filter { $0 != nil }.map { $0 } // 此处:将非可选类型'CGPoint'与nil比较始终返回true .subscribe { point in print(point.element) // 表达式从'CGPoint?'隐式转换为Any }.disposed(by: bag)
- 类型自动提升的坑:你通过
map返回的是非可选的CGPoint,但接下来的filter { $0 != nil }触发了Swift的自动类型转换——因为你在和nil做比较,编译器会默认把CGPoint包装成CGPoint?(可选类型),以此让代码能通过编译。这就导致整个序列的元素类型从CGPoint变成了CGPoint?。 - 无意义警告的原因:编译器之所以警告“将非可选类型'CGPoint'与nil比较始终返回true”,是因为原本的非可选值永远不可能等于
nil,这个比较逻辑上完全冗余,只是编译器帮你做了类型兼容而已。 - subscribe里的可选问题:后面的
map { $0 }并没有改变元素类型,还是CGPoint?。另外要注意,RxSwift的Event类型本身的element属性就是可选的(只有Next事件携带元素,Completed/Error事件没有),所以这里的point.element会呈现出可选嵌套的特性,最终触发隐式转换警告。
第二个代码片段的问题解析
let tapEvent: ControlEvent<UITapGestureRecognizer> = chargingView.rx.tapGesture() tapEvent.map { _ in return CGPoint() }.flatMap { Observable.from(optional: $0) } .subscribe { point in print(point.element)
这里的核心问题还是参数类型不匹配导致的自动包装:Observable.from(optional:)方法要求传入的参数是可选类型(T?),但你传入的是CGPoint(非可选),所以编译器自动把CGPoint包装成CGPoint?来适配方法参数。不过其实这里用from(optional:)完全没必要,因为你传入的是肯定有值的非可选类型。
优化后的写法
针对第一个例子(去掉冗余操作)
既然map返回的都是非可选的CGPoint,完全不需要过滤和二次映射,直接用针对性的订阅方法即可:
let tapEvent: ControlEvent<UITapGestureRecognizer> = chargingView.rx.tapGesture() tapEvent.map { _ in CGPoint() } .subscribe(onNext: { point in // 这里的point直接是非可选的CGPoint print(point) }) .disposed(by: bag)
subscribe(onNext:)可以直接拿到序列发射的非可选元素,比订阅Event更简洁直观。
针对第二个例子(替换合适的Observable创建方法)
如果需要把非可选值转成Observable,用Observable.just()就好,它接受非可选参数,返回对应的Observable:
let tapEvent: ControlEvent<UITapGestureRecognizer> = chargingView.rx.tapGesture() tapEvent.map { _ in CGPoint() } .flatMap { Observable.just($0) } .subscribe(onNext: { point in print(point) }) .disposed(by: bag)
总结
- 你遇到的“非可选变可选”大多是Swift编译器的自动类型提升导致的:当你把非可选值和
nil比较,或者传给需要可选参数的方法时,编译器会自动包装成可选类型。 - RxSwift的
Event类型的element属性本身就是可选的,这是事件机制的特性(只有Next事件有元素),如果想直接拿到非可选元素,推荐使用subscribe(onNext:)这类针对性的订阅方法。
内容的提问来源于stack exchange,提问作者Vyacheslav
相关产品推荐
相关产品推荐

