RxSwift实现KVO及一些概念简介

football-shoes.jpeg

1. KVO简介

在iOS开发中,苹果提供了许多机制给我们进行回调。KVO(key-value-observing)是一种十分有趣的回调机制,在某个对象注册监听者后,在被监听的对象发生改变时,对象会发送一个通知给监听者,以便监听者执行回调操作。最常见的KVO运用时监听UIScrollView对象的contentOffset属性,来完成用户滚动时动态改变某些空间的属性实现效果,例如导航栏颜色渐变、下啦刷新等效果。

2. KVO使用

KVO的使用非常简单,使用KVO的要求时对象能支持KVC -- 在OC和swift中,所有NSObject子类都支持KVC。例如上述的导航栏例子,我们为tableView添加一个监听者viewController,在滑动列表的时候,会计算当前列表的滚动偏移量,然后改变导航栏的背景色透明度,如下代码所示,

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.addObserver(self, forKeyPath: "contentOffset", options: [.new, .old], context: nil)
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    let offsetY = tableView.contentOffset.y
    let delta = offset / 64.0 + 1.0
    self.navigationBar.alpha = delta
}

3. KVO的弊端

使用KVO有其方便之处,不过显而易见的弊端在于要写太多的代码,特别是要观察多个对象值的改变的时候,开发者需要在回调方法中写很多的if-else判断,比较好的方法是将KVO的代码封装起来;另外一点就是KVO只能用在NSObject的子类中,这在swift中有一定的局限性,因为swift中不仅有引用类型,还有诸如struct和enum这样的值类型,而KVO不能作用于这些类型上面。

4. 使用RxSwift编写KVO代码

RxSwift提供了很多的组件和对象,开发者可以通过RxSwift来实现KVO的功能,主要有如下3中方式,

4.1 使用rx.observe

现假设有一个Person数据结构,如下代码定义,

class Person: NSObject {
    var name: String = ""
    var height: CGFloat = 1.80
    var address: String = ""
}

使用rx.observe的代码如下所示,

let p1 = Person()
p1.name = "flion"
p1.height = 190
p1.address = "china"
p1.rx.observe(String.self, "address").subscribe(onNext: { value in
    print("new address is \(value)")
}).disposed(by: disposeBag)

p1.address = "usa"

使用rx.observe同样存在着原生KVO所面临的问题,即rx.observe只能作用于NSObject子类的class类型,而不能作用于struct和enum。所以为了能更通用一点,再继续看下面的方法吧。

4.2 使用PublishSubject

如果你也用过ReactiveCocoa,桥接非RAC世界的东西到RAC世界,那么你应该了解Subject,显然RxSwift中也有Subject这样的概念。配合swift的didSet方法,可以如下代码所示使用Subject,

struct Person {
    var name: String = ""
    var height: CGFloat = 180
    var address: String = "" {
        didSet {
            addressSubject.onNext(address)
        }
    }
    var addressSubject = PublishSubject<String>()
}

let p2 = Person()
p2.name = "flion"
p2.height = 190
p2.address = "china"
p2.addressSubject.asObservable().subscribe(onNext: { value in
    print("new address is \(value)")
}).dispose(by: disposeBag)

p2.address = "usa"

4.3 使用Variable

在RxSwift中,还提供了一个更好的解决方案,那就是Variable,如下代码所示,

struct Person {
    var name: String = ""
    var height: CGFloat = 190
    var address: String = "" {
        get {
            return addressVariable.value
        }

        set {
            addressVariable.value = newValue
        }
    }
    var addressVariable = Variable<String>("")
}

可以看出来,使用Variable,代码简洁了很多,笔者比较提倡这种写法。

5. 关于RxSwift实现KVO的总结

在上述的范例中,我们用到了RxSwift中的Subject和Variable等概念,读者朋友可能有点迷惑,在此,笔者补充一点简单的概念,希望能够给读者解答一些疑惑。

5.1 关于Subject

在RxSwift中Observable是可观察的序列,Observable就像是一个水管,会源源不断地冒出水来。Subject就像一个水龙头,它可以套在水管上,接收Observable上面的事件;但是作为水龙头,它的下游还可以被其他的Observer订阅,即subscribe。也就是说Subject既可以像Observable一样发送事件,也可以像Observer一样订阅事件。

在RxSwift中有3种Subject,分别是,

  • PublishSubject 它仅仅会发送observer订阅之后的事件,也就是说如果sequence上有.Next的到来,但这个时候某个observer还没有订阅它,这个observer就收不到这条信息,它只会收到它订阅之后发生的事件。
  • ReplaySubject 它和PulishSubject不同之处在于它不会漏消息,即使observer在订阅的时候已经有事件发生过了,他也会收到之前的事件序列。
  • BehaviorSubject 当有observer在订阅一个BehaviorSubject的时候,它首先将会收到Observable上最近发送一个信号(或者是默认值),接着才会收到Observable上会发送的序列。

5.2 关于Variable

Variable是对BehaviorSubject的封装,它和BehaviorSubject不同之处在于,不能向Variable发送.Complete和.Error,它会在生命周期结束被释放的时候自动发送.Complete。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • 发现 关注 消息 RxSwift入坑解读-你所需要知道的各种概念 沸沸腾关注 2016.11.27 19:11*字...
    枫叶1234阅读 2,765评论 0 2
  • 本文章内部分图片资源来自RayWenderlich.com 本文结合自己的理解来总结介绍一下RxSwift最基本的...
    FKSky阅读 2,845评论 4 14
  • 建议学习时长: 45分钟学习方式:深入 学习目标 知道 CSS 怎么写。 知道在页面中引入 CSS。 详细介绍 C...
    知行社阅读 455评论 0 3
  • 输入此题其实脑中一片空白,我自己也不清楚自己是要表达什么。我只知道我似乎在假意悲欢。 我曾经幻想过走许多许多的路,...
    假意悲欢阅读 403评论 0 1
  • 人们都在喜怒哀乐中走走停停, 不知道下一站会遇到什么, 只知道 相识不易,珍惜现在。
    Y_Nicole阅读 175评论 0 0