RxSwift(一)----Observables
RxSwift
作为异步编程和事件驱动的iOS三方库.在平时的app中,我们需要同时处理图片加载,按钮点击,音视频输出,键盘弹出等异步事件.
我们可以通过通知
,代理
,GCD
,闭包
来处理这些异步事件,
这些API种类繁多且繁琐,使用RxSwift
可以很好解决这些问题.
Observables作为Rx最核心的对象,可以理解为可观察的,可观察的序列和序列,跟流相似.
他会产生三种事件.next()
,.error()
和.completed
事件.
上图表示含有三个元素的序列.
表示产生三个.next()
事件的序列,并正常结束,产生.completed
事件.
表示产生三个.next()
事件的序列,发生错误,产生.error()
事件,终止序列.
Observables
具有以下特点:
-
observable
会产生带有元素的.next()
事件,并一直这样. -
observable
会产生.error()
事件,终止序列. -
observable
会产生Observables
事件,也会终止序列. - 当序列一旦终止,就不会产生事件.
public enum Event {
/// Next element is produced.
case next(Element)
/// Sequence terminated with an error.
case error(Swift.Error)
/// Sequence completed successfully.
case completed
}
创建序列
let one = 1
let two = 2
let three = 3
let observable = Observable.just(one)
创建带有唯一元素1的序列.
let observable2 = Observable.of(one, two, three)
创建带有三个元素的序列.也可以传入数组
let observable3 = Observable.of([one, two, three])
如果采用是这样:
let observable4 = Observable.from([one, two, three])
元素类型还是Int并不是[Int].
订阅序列
上面的序列并不会产生事件,因为我们并没有订阅序列,序列订阅过后才会产生事件.
let observable2 = Observable.of(one, two, three)
observable2.subscribe { event in
print(event)
}
我们也可以获取.next()
事件的元素.
let observable2 = Observable.of(one, two, three)
observable2.subscribe { event in
if let element = event.element {
print(element)
}
}
上面是对.next()
,.completed
和.error()
事件一起订阅,我们也可以对其单独订阅.
Observable.of(one, two, three).subscribe(onNext: { _ in
print("-------onNext--------")
}, onError: { error in
print("-------error--------")
}, onCompleted: {
print("-------onCompleted--------")
})
有一种特殊序列他只会产生.completed
事件.
// 0个元素,只有completed事件
let observable5 = Observable.empty()
observable5.subscribe(onNext: { _ in
print("-------onNext--------")
}, onError: { error in
print("-------error--------")
}, onCompleted: {
print("-------onCompleted--------")
})
还有一种序列从不会终止的序列,称为无限序列.
let observable6 = Observable.never()
.subscribe(onNext: { _ in
print("1111------onNext------")
}, onError: { _ in
print("1111------onError------")
}, onCompleted: {
print("1111------onCompleted------")
})
序列我们需要对其进行内存管理,不然会造成内存泄漏
let observable2 = Observable.of(one, two, three)
let sub = observable2.subscribe { event in
if let element = event.element {
print(element)
}
}
sub.dispose()
我们也可以对其统一管理:
let bag = DisposeBag()
let observable2 = Observable.of(one, two, three)
observable2.subscribe { event in
print(event)
}
.disposed(by: bag)
我们可以自定义事件.
enum MyError: Error {
case loginError
}
let bag = DisposeBag()
Observable.create { observer -> Disposable in
observer.onNext(1)
observer.onError(MyError.loginError)
observer.onCompleted()
observer.onNext(2)
return Disposables.create()
}
.subscribe(onNext: { _ in
print("-------onNext--------")
}, onError: { error in
print("-------error--------")
}, onCompleted: {
print("-------onCompleted--------")
}) {
print("-------disposed--------")
}
.disposed(by: bag)
创建序列工厂
我们可以延迟对其其订阅者来说穿件序列.
// observable 工厂
var flip = false
// 2
let factory: Observable = Observable.deferred {
// 3
flip = !flip
// 4
if flip {
return Observable.of(1, 2, 3)
} else {
return Observable.of(4, 5, 6)
}
}
for _ in 0...3 {
factory.subscribe(onNext: {
print($0, terminator: "")
})
.disposed(by: bag)
print()
}
特征序列
有些特殊的序列,完全可以可以用上面的方式表示,但是这样不够方便和明确,这里有三种特征序列:Single
,Maybe
和Completable
.
-
Single
只会发出.success(value)
和.error
事件,像下载序列. -
Completable
只会发出.completed
和.error
事件,不会发出元素,像文件写入序列. -
Maybe
它是Single
和Completable
的结合体,可能发出.success(value)
,.error
或者.completed
事件
enum FileError: Error {
case fileNotFound, fileNotReachable,fileNotEncode
}
Single.create { single -> Disposable in
guard let path = Bundle.main.path(forResource: "test", ofType: "txt") else {
single(.error(FileError.fileNotFound))
return Disposables.create()
}
guard let data = FileManager.default.contents(atPath: path) else {
single(.error(FileError.fileNotReachable))
return Disposables.create()
}
guard let contents = String(data: data, encoding: String.Encoding.utf8) else {
single(.error(FileError.fileNotEncode))
return Disposables.create()
}
single(.success(contents))
return Disposables.create()
}
.subscribe { event in
switch event {
case .success(let contents):
print(contents)
case .error(let error):
print(error)
}
}
.disposed(by: bag)