iOS DeveloperRxSwift学习

实现一个需求 —— 使用 RxSwift 订阅 UIView 的

2017-04-13  本文已影响206人  sim_cai

最近在做项目的时候,遇到了一个需求。我有三个 View(View1, View2, View3),View1 和 View2 其中一个显示,View3 就显示。

稍微思考了一下,觉得订阅 isHidden 属性的改变,然后通过 CombineLatest 组合 Observable 来实现。

问题

而问题就来了。。。

14907957629836.jpg

isHidden 居然是个 UIBindingObserver<UIView, Bool>

尝试使用 KVO

我在使用 OC 时,会使用 ReactiveCocoa 。而在 ReactiveCocoa 我经常使用 KVO 去监控属性。或者在 RxSwift 也有类似的方法吧?

14907963190486.jpg

好像的确有类似的东西,那就到源码中查看怎么使用吧。。。

14907966551999.jpg

从这些注释,大概知道了使用方法,那就开干吧。。。

14907975018713.jpg

只打印了 next(Optional(false)), 并不能监控到 isHidden 值的变化=。=

为什么呢?难道我使用方法不对?找找可参照的例子。
KVOObservableTests.swift 找到了一段测试代码:

14907981189220.jpg

注意,这里的属性都使用了 dynamic , 感觉好像抓到了些什么?先尝试定义一个类试试看。

14907963190486.jpg

起作用了😎,那把 dynamic 删了呢?

14907984225211.jpg

又不好使了😔 为什么呢?
其实喵神在《Swift 开发必备 Tips》中就提过这个问题。

14907990537387.jpg

所以,只能另想办法了😒

使用 methodInvoked

还记得 UITextField 经常使用的 text 属性么?它又是怎么实现的呢?

14907995154959.jpg

查看源码,发现它使用了 UIControlvalue 方法。继续往下看。。。

14907997006995.jpg

这里是通过监控控件事件来实现的。。🤔那么 textField.rx.text.subscribe 同样存在一个问题

textField.text = "test"

这样的操作,也是没法得到事件的。。

但可以从这个段代码中得到给启发,我是否可以通过订阅方法处理来完成我想要的需求呢?我们在设置属性时必然会走 set 方法。

14908003089486.jpg

嗯,这个好像是我们需要的方法,那就看看能否实现吧。

14908006443769.jpg

好像起作用了,但我们可以做进一步的优化。我希望事件就给我返回个 Bool,而且包含一开始的默认属性。

14908009585593.jpg

这样就得到我想要的结果了🙃,但我可以让它变得更好用点,把它封装到 rx 中作为一个 hidden 属性好了

extension Reactive where Base: UIView {
    
    var hidden: Observable<Bool> {
        return self.methodInvoked(#selector(setter: self.base.isHidden))
            .map { event -> Bool in
                guard let isHidden = event.first as? Bool else {
                    fatalError()
                }
                
                return isHidden
            }
            .startWith(self.base.isHidden)
    }
    
    
}
14908014060346.jpg

嗯,现在就可以愉快的订阅 hidden 属性了 (^-^)V

如果大家有更好的方法,欢迎分享讨论。

最后:欢迎讨论、批评、指错。

上一篇下一篇

猜你喜欢

热点阅读