最近再重新學習swift,從OC的RAC轉到Swift的RAC方法調用大變樣,各種的不適應。
簡單了解
轉換的類型有:
RACSignal 和 SignalProducer、 Signal
RACCommand 和 Action
RACScheduler 和 SchedulerType
RACDisposable 和 Disposable
需使用的頭文件
import ReactiveCocoa
import Result
import ReactiveSwift
框架組成:
1.事件(Event)
2.監聽器(Observer)
3.清潔者(Disposable)
4.信號(Signal)
5.管道:(Pipes)
6.信號生產者:(Signal Producers)
7.緩沖:(Buffers)
8.動作:(Actions)
9.屬性:(Properties)
10.調度器:(Schedulers)
從OC的RAC轉到Swift的RAC方法調用大變樣.
1.冷信號
func bindSignal1(){
//1.冷信號
let producer = SignalProducer<String, NoError>.init { (observer, _) in
print("新的訂閱,啟動操作")
observer.send(value: "Hello")
observer.send(value: "World")
observer.sendCompleted()
}
//創建觀察者 (多個觀察者觀察會有副作用)
let sub1 = Observer<String, NoError>(value: {
print("觀察者1接受信號\($0)")
})
let sub2 = Observer<String, NoError>(value: {
print("觀察者2接受信號\($0)")
})
//觀察者訂閱信號
print("觀察者1訂閱信號")
producer.start(sub1)
print("觀察者2訂閱信號")
producer.start(sub2)
}
2.熱信號
func bindSignal2(){
//2.熱信號 (通過管道創建)
let (signalA, observerA) = Signal<String, NoError>.pipe()
let (signalB, observerB) = Signal<Int, NoError>.pipe()
Signal.combineLatest(signalA,signalB).observeValues { (value) in
print("兩個熱信號收到的值\(value.0) + \(value.1)")
}
//訂閱信號要在send之前
signalA.observeValues { (value) in
print("signalA : \(value)")
}
observerA.send(value: "sssss")
// observerA.sendCompleted()
observerB.send(value: 2)
// observerB.sendCompleted()
observerB.send(value: 100)
//不sendCompleted和sendError 熱信號一直激活
// observerB.sendCompleted()
}
3.監聽文本框
func bindSignal3(){
//2文本輸入框的監聽
nameTF.reactive.continuousTextValues.observeValues { (text) in
print(text ?? "")
}
//監聽黏貼進來的文本
let result = nameTF.reactive.values(forKeyPath: "text")
result.start { (text) in
print(text)
}
//按鈕監聽
loginBtn.reactive.controlEvents(.touchUpInside).observeValues { (button) in
print("點擊ann")
}
}
4.信號合并
合成后的新事件流只有在收到每個合成流的至少一個值后才會發送出去。接著就會把每個流的最新的值一起輸出。
func bindSignal4(){
//4.信號合并 兩個要被訂閱combineLatest 才能被訂閱,被訂閱后,合并中其中一個sendNext都會激活訂閱
let (signalA, observerA) = Signal<String, NoError>.pipe()
let (signalB, observerB) = Signal<Array<Any> , NoError>.pipe()
Signal.combineLatest(signalA, signalB).observeValues { (value) in
print("合并的信號:\(value)")
}
observerA.send(value: "xxx")
observerA.sendCompleted()
observerB.send(value: ["sdsd","ddddd"])
observerB.sendCompleted()
}
5.信號聯合
zip中的信號都要被訂閱才能激活,意味著如果是一個流的第N個元素,一定要等到另外一個流第N值也收到才會一起組合發出。
func bindSignal5(){
//5.信號聯合
let (signalA, observerA) = Signal<String, NoError>.pipe()
let (signalB, observerB) = Signal<String, NoError>.pipe()
//兩個到需要訂閱 才激活zip
Signal.zip(signalA, signalB).observeValues { (value) in
print("zip: \(value)")
}
observerA.send(value: "1")
// observerA.sendCompleted()
observerB.send(value: "2")
// observerB.sendCompleted()
observerB.send(value: "cc")
observerA.send(value: "dd")
}
6.調度器
func bindSiganl6() {
//6.調度器
QueueScheduler.main.schedule(after: Date.init(timeIntervalSinceNow: 3)) {
print("主線程3秒過去了")
}
QueueScheduler.init().schedule(after: Date.init(timeIntervalSinceNow: 2)) {
print("子線程2秒過去了")
}
}
7.通知
func bindSignal7(){
//7.通知
NotificationCenter.default.reactive.notifications(forName: Notification.Name(rawValue: "UIKeyboardWillShowNotification"), object: nil).observeValues { (notification) in
print("鍵盤彈起")
}
NotificationCenter.default.reactive.notifications(forName: Notification.Name(rawValue:"UIKeyboardWillHideNotification"), object: nil).observeValues { (notification) in
print("鍵盤收起")
}
}
8.KVO
func bindSignal8(){
//8KVO
let result = self.nameTF.reactive.values(forKeyPath: "text")
result.start { (text) in
print(text);
}
}
9.迭代器
func bindSignal9() {
//9.迭代器
let array:[String] = ["name1", "name2"]
var arrayIterator = array.makeIterator()
while let temp = arrayIterator.next() {
print(temp)
}
//swift系統自帶
array.forEach { (value) in
print(value)
}
}
10.on
可以通過 on來觀察signal,生成一個新的信號,即使沒有訂閱者也會被觸發。
和 observe相似,也可以只觀察你關注的某個事件。
需要提到的是 producer要started后才會觸發。
let signal = SignalProducer<String , NoError>.init { (obsever, _) in
obsever.send(value: "ddd")
obsever.sendCompleted()
}
//可以通過 on來觀察signal,生成一個新的信號,即使沒有訂閱者(sp.start())也會被觸發。
let sp = signal.on(starting: {
print("開始")
}, started: {
print("結束")
}, event: { (event) in
print("Event: \(event)")
}, failed: { (error) in
print("error: \(error)")
}, completed: {
print("信號完成")
}, interrupted: {
print("信號被中斷")
}, terminated: {
print("信號結束")
}, disposed: {
print("信號清理")
}) { (value) in
print("value: \(value)")
}
sp.start()
打印結果:
開始
Event: VALUE ddd
value: ddd
Event: COMPLETED
信號完成
信號結束
信號清理
結束
11.Map
Map映射 用于將一個事件流的值操作后的結果產生一個新的事件流。
let (signal, observer) = Signal<String, NoError>.pipe()
signal.map { (string) -> Int in
return string.lengthOfBytes(using: .utf8)
}.observeValues { (length) in
print("length: \(length)")
}
observer.send(value: "lemon")
observer.send(value: "something")
12.filter
//filter函數可以按照之前預設的條件過濾掉不滿足的值
let (signal, observer) = Signal<Int, NoError>.pipe()
signal.filter { (value) -> Bool in
return value % 2 == 0
}.observeValues { (value) in
print("\(value)能被2整除")
}
observer.send(value: 3)
observer.send(value: 4)
observer.send(value: 6)
observer.send(value: 7)
13.reduce
reduce將事件里的值聚集后組合成一個值
let (signal, observer) = Signal<Int, NoError>.pipe()
//reduce后的是聚合的次數
signal.reduce(3) { (a, b) -> Int in
//a是相乘后的值 b是傳入值
print("a:\(a) b:\(b)")
return a * b
}.observeValues { (value) in
print(value)
}
observer.send(value: 2)
observer.send(value: 5)
observer.send(value: 4)
//要注意的是最后算出來的值直到輸入的流完成后才會被發送出去。
observer.sendCompleted()
14.flatten
flatten 將一個事件流里的事件流變成一個單一的事件流。新的事件流的值按照指定的策略(FlattenStrategy)由內部的事件流的值組成。
被壓平的值按照會變成外層的流的類型。比如:一個SignalProducers里的Signal,被flatten后的類型是SignalProducers。
15.合并
簡單的說就是merge
按照時間順序組成,concat
則是按照里面整個流順序組合。latest
是只記錄最近一次過來的值的那個流。
1 .merge
.Merge 策略將每個流的值立刻組合輸出。無論內部還是外層的流如果收到失敗就終止。
let (producerA, lettersObserver) = Signal<String, NoError>.pipe()
let (producerB, numbersObserver) = Signal<String, NoError>.pipe()
let (signal, observer) = Signal<Signal<String, NoError>, NoError>.pipe()
signal.flatten(.merge).observeValues { (value) in
print("value: \(value)")
}
observer.send(value: producerA)
observer.send(value:producerB)
observer.sendCompleted()
lettersObserver.send(value:"a") // prints "a"
numbersObserver.send(value:"1") // prints "1"
lettersObserver.send(value:"b") // prints "b"
numbersObserver.send(value:"2") // prints "2"
lettersObserver.send(value:"c") // prints "c"
numbersObserver.send(value:"3") // prints "3"
2 .concet
Concat 策略是將內部的SignalProducer排序。外層的producer是馬上被started。隨后的producer直到前一個發送完成后才會start。一有失敗立即傳到外層。
let (signalA, lettersObserver) = Signal<Any, NoError>.pipe()
let (signalB, numberObserver) = Signal<Any, NoError>.pipe()
let (siganl, observer) = Signal<Signal<Any, NoError>, NoError>.pipe()
siganl.flatten(.concat).observeValues { (value) in
print("value: \(value)")
}
observer.send(value: signalA)
observer.send(value: signalB)
observer.sendCompleted()
lettersObserver.send(value: "dddd")//dddd
numberObserver.send(value: 33) //不打印
lettersObserver.send(value: "sss")//sss
lettersObserver.send(value: "ffff")//ffff
lettersObserver.sendCompleted()
//要前一個信號執行完畢后,下一個信號才能被訂閱
numberObserver.send(value: 44)// 44
3 .Latest
.latest只接收最新進來的那個流的值。
let (signalA, lettersObserver) = Signal<Any, NoError>.pipe()
let (signalB, numberObserver) = Signal<Any, NoError>.pipe()
let (siganl, observer) = Signal<Signal<Any, NoError>, NoError>.pipe()
siganl.flatten(.latest).observeValues { (value) in
print("value: \(value)")
}
observer.send(value: signalA)
// observer.send(value: signalB)
lettersObserver.send(value: "dddd") //dddd
numberObserver.send(value: 33) //不打印
lettersObserver.send(value: "sss") //sss
observer.send(value: signalB)
//只接受最近進來的信號
numberObserver.send(value: 44) //44
lettersObserver.send(value: "ffff") // 不打印
16.flatMapError
flatMapError捕捉一個由SignalProducer產生的失敗,然后產生一個新的SignalProducer代替。
let (signal, observer) = Signal<Any, NSError>.pipe()
let error = NSError.init(domain: "domian", code: 0, userInfo: nil)
signal.flatMapError { (value) -> SignalProducer<Any, NoError> in
return SignalProducer<Any, NoError>.init({ () -> String in
return "sssss"
})
}.observeValues { (value) in
print(value)
}
observer.send(value: 3333)
observer.send(value: 444)
observer.send(error: error)
17.retry
retry用于按照指定次數,在失敗時重啟SignalProducer。
var tries = 0
let limit = 2
let error = NSError.init(domain: "domian", code: 0, userInfo: nil)
let signal = SignalProducer<String, NSError >.init { (observer, _) in
tries += 1
if tries < limit {
observer.send(error: error)
}else{
observer.send(value: "Success")
observer.sendCompleted()
}
}
// retry用于按照指定次數,在失敗時重啟SignalProducer。
signal.on(failed:{e in
print("Failure")
}).retry(upTo:3).start { (event) in
switch event {
case .completed:
print("Complete")
//判斷輸出值是否相等
case .value("Success"):
print("ddd")
case .interrupted:
print("interrupted")
case .failed(error):
print(error)
default:
break
}
}
18.continuousTextValues
usernameTextField.reactive就是把usernameTextField變成可響應的,而continuousTextValues就是text值的信號。
self.nameTF.reactive.continuousTextValues.observe { (value) in
print(value)
}
19.按鈕點擊事件和其他事件轉信號
self.loginBtn.reactive.controlEvents(.touchUpInside).observe { (button) in
print("點擊按鈕")
}
20.屬性的綁定
<~運算符是提供了幾種不同的綁定屬性的方式。注意這里綁定的屬性必須是 MutablePropertyType類型的。
property <~ signal 將一個屬性和信號綁定在一起,屬性的值會根據信號送過來的值刷新。
property <~ producer 會啟動這個producer,并且屬性的值也會隨著這個產生的信號送過來的值刷新。
property <~ otherProperty將一個屬性和另一個屬性綁定在一起,這樣這個屬性的值會隨著源屬性的值變化而變化。
var userName: MutableProperty<String?> = MutableProperty<String?>(nil)
var userPw : MutableProperty<String?> = MutableProperty<String?>(nil)
var logAction = Action<Void, Void, NoError> { (input: Void) -> SignalProducer< Void , NoError> in
return SignalProducer{ (observer, disposable) in
observer.send(value: ())
observer.sendCompleted()
}
}
self.viewModel!.userName <~ nameTF.reactive.textValues
self.viewModel!.userPw <~ pwTF.reactive.textValues
loginBtn.reactive.pressed = CocoaAction<UIButton>((viewModel?.logAction)!)