RxSwift之深入解析如何创建观察者Observer

举报
Serendipity·y 发表于 2022/02/16 22:46:50 2022/02/16
【摘要】 一、什么是观察者? “观察者”是用来监听事件,然后它需要这个事件做出响应。例如:弹出提示框就是观察者,它对点击按钮这个事件做出响应。 那么,什么是观察者呢?其实,响应事件的都是观察者。 当室...

一、什么是观察者?

  • “观察者”是用来监听事件,然后它需要这个事件做出响应。例如:弹出提示框就是观察者,它对点击按钮这个事件做出响应。

在这里插入图片描述

  • 那么,什么是观察者呢?其实,响应事件的都是观察者。
    • 当室温高于 33 度时,打开空调降温,打开空调降温就是观察者 Observer:

在这里插入图片描述

    • 当《海贼王》更新一集时,我们就立即观看这一集,观看这一集就是观察者 Observer:

在这里插入图片描述

    • 当取到 JSON 时,将它打印出来,将它打印出来就是观察者 Observer:

在这里插入图片描述

    • 当任务结束后,提示用户任务已完成,提示用户任务已完成就是观察者 Observer:

在这里插入图片描述

二、如何创建观察者?

  • 和 Observable 一样,框架已经帮我们创建好了许多常用的观察者。例如:view 是否隐藏,button 是否可点击, label 的当前文本,imageView 的当前图片等。
  • 另外,有一些自定义的观察者是需要我们自己创建的。例如,创建一个弹出提示框的的观察者:
tap.subscribe(onNext: { [weak self] in
    self?.showAlert()
}, onError: { error in
    print("发生错误: \(error.localizedDescription)")
}, onCompleted: {
    print("任务完成")
})

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 创建观察者最直接的方法就是在 Observable 的 subscribe 方法后面描述,事件发生时,需要如何做出响应。而观察者就是由后面的 onNext,onError,onCompleted 的这些闭包构建出来的。

三、AnyObserver

  • AnyObserver 可以用来描叙任意一种观察者。
  • 打印网络请求结果:
URLSession.shared.rx.data(request: URLRequest(url: url))
    .subscribe(onNext: { data in
        print("Data Task Success with count: \(data.count)")
    }, onError: { error in
        print("Data Task Error: \(error)")
    })
    .disposed(by: disposeBag)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 可以看作是:
let observer: AnyObserver<Data> = AnyObserver { (event) in
    switch event {
    case .next(let data):
        print("Data Task Success with count: \(data.count)")
    case .error(let error):
        print("Data Task Error: \(error)")
    default:
        break
    }
}

URLSession.shared.rx.data(request: URLRequest(url: url))
    .subscribe(observer)
    .disposed(by: disposeBag)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 用户名提示语是否隐藏:
sernameValid
    .bind(to: usernameValidOutlet.rx.isHidden)
    .disposed(by: disposeBag)

  
 
  • 1
  • 2
  • 3
  • 可以看作是:
let observer: AnyObserver<Bool> = AnyObserver { [weak self] (event) in
    switch event {
    case .next(let isHidden):
        self?.usernameValidOutlet.isHidden = isHidden
    default:
        break
    }
}

usernameValid
    .bind(to: observer)
    .disposed(by: disposeBag)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

四、Binder

  • Binder 主要有以下两个特征:
    • 不会处理错误事件;
    • 确保绑定都是在给定 Scheduler 上执行(默认 MainScheduler)。
  • 一旦产生错误事件,在调试环境下将执行 fatalError,在发布环境下将打印错误信息。

① 示例

  • 在上文中的 AnyObserver ,我们举了这样一个例子:
let observer: AnyObserver<Bool> = AnyObserver { [weak self] (event) in
    switch event {
    case .next(let isHidden):
        self?.usernameValidOutlet.isHidden = isHidden
    default:
        break
    }
}

usernameValid
    .bind(to: observer)
    .disposed(by: disposeBag)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 由于这个观察者是一个 UI 观察者,所以它在响应事件时,只会处理 next 事件,并且更新 UI 的操作需要在主线程上执行。因此一个更好的方案就是使用 Binder:
let observer: Binder<Bool> = Binder(usernameValidOutlet) { (view, isHidden) in
    view.isHidden = isHidden
}

usernameValid
    .bind(to: observer)
    .disposed(by: disposeBag)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • Binder 可以只处理 next 事件,并且保证响应 next 事件的代码一定会在给定 Scheduler 上执行,这里采用默认的 MainScheduler。

② 复用

  • 由于页面是否隐藏是一个常用的观察者,所以应该让所有的 UIView 都提供这种观察者:
extension Reactive where Base: UIView {
  public var isHidden: Binder<Bool> {
      return Binder(self.base) { view, hidden in
          view.isHidden = hidden
      }
  }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
usernameValid
    .bind(to: usernameValidOutlet.rx.isHidden)
    .disposed(by: disposeBag)

  
 
  • 1
  • 2
  • 3
  • 这样不必为每个 UI 控件单独创建该观察者,这就是 usernameValidOutlet.rx.isHidden 的由来,许多 UI 观察者都是这样创建的:
    • 按钮是否可点击 button.rx.isEnabled:
extension Reactive where Base: UIControl {
  public var isEnabled: Binder<Bool> {
      return Binder(self.base) { control, value in
          control.isEnabled = value
      }
  }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
    • label 的当前文本 label.rx.text:
extension Reactive where Base: UILabel {
  public var text: Binder<String?> {
      return Binder(self.base) { label, text in
          label.text = text
      }
  }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 也可以用这种方式来创建自定义的 UI 观察者。

文章来源: blog.csdn.net,作者:Serendipity·y,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/Forever_wj/article/details/120893200

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。