RxSwift學(xué)習(xí)(二)

前言
RxSwift的目的是讓數(shù)據(jù)/事件流和異步任務(wù)能夠更方便的序列化處理往毡,能夠使用Swift進(jìn)行響應(yīng)式編程拖吼。

本文的目的:

  • 介紹RxSwift的核心思想
  • 講解RxSwift的基礎(chǔ)使用
  • 介紹RxSwift的優(yōu)點(diǎn)

RxSwift的核心是想是Observable<Element> sequence惊来,Observable表示可監(jiān)聽或者可觀察,也就是說(shuō)RxSwift的核心思想是可監(jiān)聽的序列砾嫉。并且杉编,Observable sequence可以接受異步信號(hào),也就是說(shuō)赌厅,信號(hào)是可以異步給監(jiān)聽者的穷绵。

  • Observable(ObservableType)SequenceType類似
  • ObservableType.subscribeSequenceType.generate類似
  • 由于RxSwift支持異步獲得信號(hào),所以用ObservableType.subscribe特愿,這和indexGenerator.next()類似仲墨。

本文把RxSwift中的序列的每一個(gè)Element成為信號(hào),因?yàn)楫惒降?code>Element是與時(shí)間相關(guān)的,稱作信號(hào)更好理解一點(diǎn)揍障。

RxSwift中目养,ObservableType.subscribe的回調(diào)(新的信號(hào)到來(lái))一共有三種

enum Event<Element>  {
    case Next(Element)      // 新的信號(hào)到來(lái)
    case Error(ErrorType)   // 信號(hào)發(fā)生錯(cuò)誤,序列不會(huì)再產(chǎn)生信號(hào)
    case Completed          // 序列發(fā)送信號(hào)完成毒嫡,不會(huì)再產(chǎn)生新的信號(hào)
}
protocol ObserverType {
    func on(event: Event<Element>) //監(jiān)聽所有的信號(hào)
}

取消監(jiān)聽

Observable分為兩種

  1. 在有限的時(shí)間內(nèi)會(huì)自動(dòng)結(jié)束(Completed/Error),比如一個(gè)網(wǎng)絡(luò)請(qǐng)求當(dāng)作一個(gè)序列癌蚁,當(dāng)網(wǎng)絡(luò)請(qǐng)求完成的時(shí)候,Observable自動(dòng)結(jié)束兜畸,資源會(huì)被釋放
    2.信號(hào)不會(huì)自己結(jié)束努释,最簡(jiǎn)單的比如一個(gè)Timer,每隔一段時(shí)間發(fā)送一個(gè)新的信號(hào)過來(lái)咬摇,這時(shí)候需要手動(dòng)取消監(jiān)聽伐蒂,來(lái)釋放相應(yīng)的資源,又比如一個(gè)label.rac_text是一個(gè)Obserable,通常需要這樣調(diào)用addDisposableTo(disposeBag)來(lái)讓其在deinit肛鹏,也就是所有者要釋放的時(shí)候逸邦,自動(dòng)取消監(jiān)聽。
class Observable<Element> {
    func subscribe(observer: Observer<Element>) -> Disposable //調(diào)用Disposable的方法來(lái)取消
}

當(dāng)然在扰,除了手動(dòng)釋放缕减,RxSwift提供了一些操作符,比如takeUntil來(lái)根據(jù)條件取消

sequence
    .takeUntil(self.rx_deallocated) //當(dāng)對(duì)象要釋放的時(shí)候健田,取消監(jiān)聽
    .subscribe {
        print($0)
    }

信號(hào)處理的順序

Observable有個(gè)隱式的約定烛卧,那就是在一個(gè)信號(hào)處理完成之前,不會(huì)發(fā)送下一個(gè)信號(hào)妓局,不管發(fā)送信號(hào)的線程是并發(fā)的or串行的总放。

例如

someObservable
  .subscribe { (e: Event<Element>) in
      print("Event processing started")
      // processing
      print("Event processing ended")
  }

只會(huì)出現(xiàn)
[圖片上傳中...(正確結(jié)果.png-5f2e8d-1521776416167-0)]

不會(huì)出現(xiàn)的結(jié)果


不會(huì)出現(xiàn)這樣的結(jié)果.png

第一個(gè)例子

我們監(jiān)聽textfield的文字變化,然后好爬,Logtext局雄,當(dāng)button點(diǎn)擊的時(shí)候,取消這次監(jiān)聽

class ObservableAndCancelController : UIViewController{
    var subscription:Disposable?

    @IBOutlet weak var textfield: UITextField!
    @IBAction func cancelObserve(sender: AnyObject) {
        subscription?.dispose()
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        subscription = textfield.rx_text.subscribeNext { (text) in
            print(text)
        }
    }
}

RxSwiftextensiton的方式存炮,為UITextfield,UIlabel等控件添加了很多可監(jiān)聽的屬性炬搭,這里的textfield.rx_text就是一個(gè)


操作符(Operators)

在上文的第一個(gè)例子里面蜈漓,你看到了監(jiān)聽信號(hào),并且log出值宫盔。事實(shí)上融虽,這樣直接處理信號(hào)的時(shí)候是很少的,很多時(shí)候灼芭,我們需要對(duì)信號(hào)進(jìn)行映射有额,過濾,這時(shí)候我們就要用到操作符了彼绷。在這個(gè)文檔里巍佑,你可以找到所有的操作符。

關(guān)于操作符效果寄悯,你可以參見http://rxmarbles.com/的可視化效果萤衰,這會(huì)給你一個(gè)更好的理解

例子二 map,filter,combineLatest

  • map 對(duì)信號(hào)(Element)進(jìn)行映射處理。比如輸入是String猜旬,影射到Bool
  • filter 對(duì)信號(hào)(Element)進(jìn)行過濾處理脆栋。返回信號(hào),和輸入的信號(hào)是同一種類型
  • combineLatest 對(duì)兩種信號(hào)的值進(jìn)行結(jié)合昔馋〕锿拢可以返回不同種類的信號(hào)糖耸。

例如

let firstObserverable = firstTextfield.rx_text.map({"first" + $0})
     let secondObserverable = secondTextfield.rx_text.filter({$0.characters.count > 3})
      _ =  Observable.combineLatest(firstObserverable, secondObserverable, resultSelector:{ ($0 + $1,$0.characters.count + $1.characters.count)}).subscribeNext { (element) in
            print("combineLatest:\(element)")
      }        

對(duì)于秘遏,每一個(gè)fistTextfield的信號(hào),在字符串開始處增加”first”嘉竟;
對(duì)secondTextfield的信號(hào)進(jìn)行過濾邦危,當(dāng)長(zhǎng)度大于3的時(shí)候,才會(huì)繼續(xù)傳遞;
對(duì)兩個(gè)信號(hào)進(jìn)行結(jié)合舍扰,取truple類型倦蚪,然后打印出來(lái)。

所以边苹,當(dāng)我在fistTextfield中陵且,輸入1234,然后secondTextfield中依次輸入abcdefg的時(shí)候

打印結(jié)果.png

例子三 創(chuàng)建一個(gè)Observable

Observerable可以用來(lái)處理任務(wù)个束,并且異步返回Event信號(hào)(Next,Error,Completion)

比如慕购,這樣一個(gè)方法

//Observable就是處理輸入,并且把description發(fā)送出去
func createObserveable(object:AnyObject?)->Observable<String?>{
    return Observable.create({ observer in
        observer.onNext(object?.description)
        observer.onCompleted()
        return NopDisposable.instance
    })
}

這樣調(diào)用

_ = createObserveable(test).subscribe({ (event) in
      switch event{
      case .Next(let value):
          print(value)
      case .Completed:
          print("Completed")
      case .Error(let error):
          print(error)
      }
  })

可以看到茬底,創(chuàng)建一個(gè)Observable相當(dāng)容易沪悲,調(diào)用Observable.create,在必要的時(shí)候發(fā)送onNext,onError,onCompleted信號(hào)阱表。然后返回一個(gè)Disposable用來(lái)取消信號(hào)

throttle/retry/distinctUntilChanged/flatMapLatest

  • throttle 忽略上一個(gè)信號(hào)的一段時(shí)間的變化,也就是說(shuō)一段時(shí)間沒有新的信號(hào)輸入殿如,才會(huì)向下發(fā)送
  • distinctUntilChanged 直到信號(hào)改變了再發(fā)送
  • retry 如果失敗贡珊,重新嘗試的次數(shù)
  • flatMapLatest 僅僅執(zhí)行最新的信號(hào),當(dāng)有新的信號(hào)來(lái)的時(shí)候涉馁,取消上一次未執(zhí)行完的整個(gè)序列

最直接的例子就是搜索门岔,通常我們想要
1.用戶用一段時(shí)間沒有輸入的時(shí)候,在進(jìn)進(jìn)行網(wǎng)絡(luò)請(qǐng)求烤送,不然網(wǎng)絡(luò)請(qǐng)求太頻繁固歪,對(duì)客戶端和服務(wù)器都是負(fù)擔(dān)
2.當(dāng)新的請(qǐng)求來(lái)的時(shí)候,如果上一個(gè)未完成胯努,則取消上一個(gè)
3.如果網(wǎng)絡(luò)失敗牢裳,能重新請(qǐng)求幾次就更好了

這時(shí)候,用RxSwift你得代碼會(huì)變的非常簡(jiǎn)單

let searchResults = searchBar.rx_text
    .throttle(0.3, scheduler: MainScheduler.instance)
    .distinctUntilChanged()
    .flatMapLatest { query -> Observable<[Repository]> in
        if query.isEmpty {
            return Observable.just([])
        }

        return doSearchAPI(query).retry(3)
            .catchErrorJustReturn([])
    }
    .observeOn(MainScheduler.instance)

這里簡(jiǎn)單講解下作用

  • throttle(0.3, scheduler: MainScheduler.instance) 保證用戶沒有輸入0.3秒后再進(jìn)行下一步
  • distinctUntilChanged() 假如0.3秒之前輸入是ab叶沛,0.3秒后還是ab,則不會(huì)進(jìn)行下一步蒲讯,只有改變了才會(huì)進(jìn)行下一步
  • flatMapLatest 保證只搜索最新的,如果之前的沒有完成灰署,會(huì)被自動(dòng)取消
  • doSearchAPI(query).retry(3) 保證判帮,如果發(fā)生錯(cuò)誤,自動(dòng)重試3次溉箕。

Schedulers

Schedulers 抽象化了線程晦墙,線程池,GCD中操作隊(duì)列肴茄,Runloop等概念晌畅。可以理解為寡痰,Schedulers就是一個(gè)執(zhí)行任務(wù)的線程抗楔。

有一點(diǎn)要注意:默認(rèn)一個(gè)Observerable在其創(chuàng)建的線程上執(zhí)行

Schedulers相關(guān)的操作符有兩個(gè)

  • observeOn(scheduler) 在一個(gè)scheduler上執(zhí)行任務(wù),使用場(chǎng)景較多
  • subscribeOn(scheduler)在一個(gè)scheduler進(jìn)行監(jiān)聽

比如:

sequence1
  .observeOn(backgroundScheduler)
  .map { n in
      print("This is performed on the background scheduler")
  }
  .observeOn(MainScheduler.instance)
  .map { n in
      print("This is performed on the main scheduler")
  }.subscribeOn(backgroundScheduler)
  .subscribeNext{ n in
      print("This is performed on the background scheduler")
  }

__ 默認(rèn)一個(gè)subscribeNext或者subscribe在其調(diào)用的線程上執(zhí)行__

Serial/Concurrent Schedulers 串行或并行

GCD的隊(duì)列很相似拦坠,并行Schedulers的任務(wù)可以并發(fā)之行连躏,串行Schedulers只能依次執(zhí)行。不過RxSwift有內(nèi)部機(jī)制贞滨,保證上文提到的信號(hào)處理的順序

RxSwift內(nèi)置的Scheduler

通常入热,使用內(nèi)置的Scheduler足矣。

  • CurrentThreadScheduler(串行) 當(dāng)前線程Scheduler晓铆,默認(rèn)使用的
  • MainScheduler(串行) 主線程
  • SerialDispatchQueueScheduler 封裝了GCD的串行隊(duì)列
  • ConcurrentDispatchQueueScheduler 封裝了GCD的并行隊(duì)列勺良,這個(gè)在有任務(wù)要在后臺(tái)執(zhí)行的時(shí)候很有用
  • OperationQueueScheduler 封裝了NSOperationQueue
    例子四,在后臺(tái)Scheduler之行任務(wù)尤蒿,然后在主線程上更新UI

Variable

Variable表示一個(gè)可監(jiān)聽的數(shù)據(jù)結(jié)構(gòu)郑气。使用Variable,你可以監(jiān)聽數(shù)據(jù)的變化腰池,也可以把其他值綁定到它身上尾组。

當(dāng)Variable被釋放的時(shí)候忙芒,它會(huì)向監(jiān)聽者發(fā)送onCompleted

例子五,Variable進(jìn)行監(jiān)聽

class VariableController: UIViewController {

    @IBOutlet weak var label: UILabel!
    var timer:NSTimer?
    var count = Variable(0)
    override func viewDidLoad() {
        super.viewDidLoad()
        timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector:#selector(VariableController.updateValue) , userInfo: nil, repeats: true)
        _ = count.asObservable().subscribeNext { (num) in
            self.label?.text = "VariableValue:\(num)"
        }
    }
    func updateValue(){
        count.value = count.value + 1
    }
    override func viewDidDisappear(animated: Bool) {
        super.viewDidDisappear(animated)
        timer?.invalidate()
    }
}

數(shù)據(jù)綁定

數(shù)據(jù)綁定是開發(fā)的時(shí)候很常見的讳侨,比如根據(jù)文本的輸入動(dòng)態(tài)調(diào)整textfield的背景色呵萨,動(dòng)態(tài)調(diào)整按鈕的enable。亦或者根據(jù)textfield的輸入變化跨跨,動(dòng)態(tài)的去反饋到model層潮峦。如果你聽過MVVM,那你肯定知道勇婴,MVVM的難點(diǎn)就是ViewModelView的數(shù)據(jù)綁定問題忱嘹。

不過,使用RxSwift耕渴,數(shù)據(jù)綁定變的十分容易拘悦,你甚至可以把數(shù)據(jù)綁定到tableviewcollectionView上去。

例子六橱脸,bindTo
很簡(jiǎn)單础米,隨著Switch的開關(guān),view進(jìn)行顯示/隱藏

bindTo案例.gif

只需要一行代碼

_ = mySwitch.rx_value.bindTo(testView.rx_hidden)

例子七添诉,根據(jù)輸入屁桑,進(jìn)行View狀態(tài)綁定

我們想要實(shí)現(xiàn)這樣的狀態(tài)

  • 用戶名至少6位,小于6位栏赴,則背景色是灰色蘑斧,合法則透明
  • 密碼至少位8位,小于8位艾帐,則背景色是灰色乌叶,合法則透明
  • 當(dāng)用戶名和密碼都合法的時(shí)候,注冊(cè)按鈕enable柒爸,并且背景色變紅
綁定View案例.gif

信號(hào)的處理方式如下:

 let nameObserable = nameTextfield.rx_text.shareReplay(1).map({$0.characters.count >= 6}) 
        let pwdObserable = passwordTextfield.rx_text.shareReplay(1).map({$0.characters.count >= 8})

        _ = nameObserable.subscribeNext({ (valid) in
            self.nameTextfield.backgroundColor = valid ? UIColor.clearColor():UIColor.lightGrayColor()
        }).addDisposableTo(disposeBag)

        _ = pwdObserable.subscribeNext({ (valid) in
            self.passwordTextfield.backgroundColor = valid ? UIColor.clearColor(): UIColor.lightGrayColor()
        }).addDisposableTo(disposeBag)//addDisposableTo(disposeBag)是為了自動(dòng)釋放

        _ = Observable.combineLatest(nameObserable, pwdObserable) {$0 && $1}.subscribeNext({valid in
                if valid{
                    self.registerButton.enabled = true
                    self.registerButton.backgroundColor = UIColor.redColor()
                }else{
                    self.registerButton.enabled = false
                    self.registerButton.backgroundColor = UIColor.darkGrayColor()
                }
            }).addDisposableTo(disposeBag)
        _ = registerButton.rx_tap.shareReplay(1).subscribeNext {
            print("Button tapped")
        }

共享監(jiān)聽Sharing subscription-shareReplay

這個(gè)是很常用的,比如一個(gè)Obserable用做網(wǎng)絡(luò)請(qǐng)求事扭,通常捎稚,當(dāng)你這樣調(diào)用的時(shí)候,會(huì)創(chuàng)建兩個(gè)序列求橄,也就是會(huì)進(jìn)行兩次網(wǎng)絡(luò)請(qǐng)求今野,這是不需要的

let network = networkWithText(text)
let subscription1 = network
    .subscribeNext { n in
       //創(chuàng)建第一個(gè)序列
    }
let subscription2 = network
    .subscribeNext { n in
       //創(chuàng)建第二個(gè)序列
    }

為了共享一個(gè)序列,你只需要這這樣調(diào)用
let network = networkWithText(text).shareReplay(1)
就只會(huì)進(jìn)行一次網(wǎng)絡(luò)請(qǐng)求罐农,兩個(gè)subscription共享結(jié)果条霜,也就是shareReplay的意思

自定義可綁定屬性

上文,textfieldbutton的狀態(tài)綁定是手動(dòng)的涵亏,這無(wú)疑是不方便的宰睡。RxSwift為我們提供了一種方式蒲凶,來(lái)自定義可綁定屬性

創(chuàng)建兩個(gè)exetnsion

extension UITextField{
    var ex_validState:AnyObserver<Bool>{
        return UIBindingObserver(UIElement: self) { textfield, valid in
                textfield.backgroundColor = valid ? UIColor.clearColor():UIColor.lightGrayColor()
            }.asObserver()
    }
}
extension UIButton{
    var ex_validState:AnyObserver<Bool>{
        return UIBindingObserver(UIElement: self) { button, valid in
                button.enabled = valid
            button.backgroundColor = valid ? UIColor.redColor() : UIColor.darkGrayColor()
            }.asObserver()
    }
}

然后,上文的代碼拆内,就可以簡(jiǎn)化成三行了旋圆,So easy

 _ = nameObserable.bindTo(nameTextfield.ex_validState).addDisposableTo(disposeBag)
        _ = pwdObserable.bindTo(passwordTextfield.ex_validState).addDisposableTo(disposeBag)

        _ = Observable.combineLatest(nameObserable, pwdObserable) {$0 && $1}.bindTo(registerButton.ex_validState).addDisposableTo(disposeBag)

Driver

DriverRxSwift精心制作的,專門提供給UI層的一個(gè)接口麸恍。

利用Driver你可以

  • 利用CoreData的模型來(lái)驅(qū)動(dòng)UI
  • 利用UI的狀態(tài)來(lái)綁定其他UI的狀態(tài)

Driver能夠保證灵巧,在主線程上監(jiān)聽,因?yàn)閁IKit不是需要在主線程上操作

Tips:

RxSwift中做數(shù)據(jù)綁定有三種

  • 利用BindTo方法
  • 利用Driver(強(qiáng)烈建議使用這個(gè)抹沪,)
  • 利用KVO來(lái)手動(dòng)綁定(很少用到)

回到Driver上來(lái)刻肄,上文提到了,對(duì)于搜索融欧,我們可以這么做肄方,

let results = query.rx_text
    .throttle(0.3, scheduler: MainScheduler.instance) //延遲0.3秒
    .flatMapLatest { query in //永遠(yuǎn)只執(zhí)行最新的
        searchWithText(query)
    }

results
    .map { "\($0.count)" } 
    .bindTo(resultCount.rx_text)//綁定label
    .addDisposableTo(disposeBag)

results
    .bindTo(resultsTableView.rx_itemsWithCellIdentifier("Cell")) { (_, result, cell) in //綁定tableview
        cell.textLabel?.text = "\(result)"
    }
    .addDisposableTo(disposeBag)

那么,這有什么缺陷呢蹬癌?

假如searchWithText失敗了权她,那么整個(gè)序列就斷掉了,后面的綁定不會(huì)有任何作用
假如searchWithText是在后臺(tái)線程執(zhí)行的逝薪,那么后續(xù)綁定是在后臺(tái)線程上進(jìn)行的隅要,會(huì)崩潰
綁定了兩次,意味著會(huì)執(zhí)行兩次
于是董济,我們需要進(jìn)行額外的操作步清,來(lái)避免上述缺陷。

let results = query.rx_text
    .throttle(0.3, scheduler: MainScheduler.instance) 
    .flatMapLatest { query in
        fetchAutoCompleteItems(query)
            .observeOn(MainScheduler.instance)  // 保證在主線程(解決缺陷1)
            .catchErrorJustReturn([])           // 發(fā)生錯(cuò)誤虏肾,返回空數(shù)組(解決缺陷2)
                }
    .shareReplay(1)                             // 共享監(jiān)聽廓啊,保證只執(zhí)行一次(解決缺陷3)                                               
results
    .map { "\($0.count)" }
    .bindTo(resultCount.rx_text)
    .addDisposableTo(disposeBag)

results
    .bindTo(resultTableView.rx_itemsWithCellIdentifier("Cell")) { (_, result, cell) in
        cell.textLabel?.text = "\(result)"
    }
    .addDisposableTo(disposeBag)

利用Driver我們可以將上述過程簡(jiǎn)化

let results = query.rx_text.asDriver()        // 轉(zhuǎn)換成Driver序列
    .throttle(0.3, scheduler: MainScheduler.instance)
    .flatMapLatest { query in
        fetchAutoCompleteItems(query)
            .asDriver(onErrorJustReturn: [])  // 告訴Driver發(fā)生錯(cuò)誤怎么辦
                }

results
    .map { "\($0.count)" }
    .drive(resultCount.rx_text)               // 用Driver綁定,不需要切換到主線程
    .addDisposableTo(disposeBag)                                                            
results
    .drive(resultTableView.rx_itemsWithCellIdentifier("Cell")) { (_, result, cell) in
        cell.textLabel?.text = "\(result)"
    }
    .addDisposableTo(disposeBag)

任何滿足以下三個(gè)條件的Observer序列都可以轉(zhuǎn)換為Driver

  1. 不會(huì)因?yàn)殄e(cuò)誤就序列斷掉(比如封豪,有錯(cuò)誤谴轮,但是沒有調(diào)用onError來(lái)發(fā)送錯(cuò)誤)
    2.在主線程傻姑娘監(jiān)聽
    3.共享 side effects
    對(duì)于,使用者只需要調(diào)用asDriver(onErrorJustReturn: [])就能保證上述三點(diǎn)都實(shí)現(xiàn)了

KVO

通常的KVO吹埠,你需要在這個(gè)函數(shù)里來(lái)處理

-(void)observeValueForKeyPath:(NSString *)keyPath
                     ofObject:(id)object
                       change:(NSDictionary *)change
                      context:(void *)context

而使用RxSwift,KVO變成了這樣

view.rx_observe(CGRect.self, "frame")
    .subscribeNext { frame in
        print("Got new frame \(frame)")
    }

或者這樣

someSuspiciousViewController
    .rx_observeWeakly(Bool.self, "behavingOk")
    .subscribeNext { behavingOk in
        print("Cats can purr? \(behavingOk)")
    }

二者的區(qū)別是

rx_observe可以使用地方都可以使用rx_observeWeakly第步。rx_observeWeakly的執(zhí)行效率要低一點(diǎn),因?yàn)橐幚韺?duì)象的dealloc關(guān)系缘琅。除此之外粘都,rx_observeWeakly還可以用在weak屬性上。

在使用view.rx_observe的時(shí)候刷袍,有幾點(diǎn)要注意

由于KVO是建立在NSObject子類的基礎(chǔ)上的翩隧,你可以通過如下方法,來(lái)讓Structs支持KVO

Notification

使用RxSwift呻纹,Notification變的十分簡(jiǎn)潔

NSNotificationCenter.defaultCenter()
    .rx_notification(UITextViewTextDidBeginEditingNotification, object: myTextView)
    .map { /*do something with data*/ }
    ....

調(diào)試

使用Debug操作符堆生,會(huì)log所有的數(shù)據(jù)流

let subscription = myInterval(0.1)
    .debug("my probe")
    .map { e in
        return "This is simply \(e)"
    }
    .subscribeNext { n in
        print(n)
    }

NSThread.sleepForTimeInterval(0.5)


subscription.dispose(

你可以用自定義操作符的方式专缠,來(lái) Log

extension ObservableType {
    public func myDebug(identifier: String) -> Observable<Self.E> {
        return Observable.create { observer in
            print("subscribed \(identifier)")
            let subscription = self.subscribe { e in
                print("event \(identifier)  \(e)")
                switch e {
                case .Next(let value):
                    observer.on(.Next(value))

                case .Error(let error):
                    observer.on(.Error(error))

                case .Completed:
                    observer.on(.Completed)
                }
            }
            return AnonymousDisposable {
                   print("disposing \(identifier)")
                   subscription.dispose()
            }
        }
    }
 }

調(diào)試內(nèi)存泄漏問題

RxSwift通過RxSwift.resourceCount記錄資源分配情況,所以通常的調(diào)試方式如下

  /* 在AppDelegate方法中添加Log
    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
    */
    _ = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
        .subscribeNext { _ in
        print("Resource count \(RxSwift.resourceCount)")
    }

然后

1.進(jìn)入相關(guān)界面顽频,進(jìn)行正常操作
2.退出界面
3.觀察RxSwift.resourceCount
4.在進(jìn)入同一個(gè)界面藤肢,退出
5.觀察RxSwift.resourceCount


使用心得

1.時(shí)刻牢記,使用RxSwift糯景,盡量把所有的任務(wù)(可以理解為方法)抽象成Obserable(序列)和Obserable創(chuàng)建者嘁圈,監(jiān)聽者
2.能用數(shù)據(jù)綁定的(bindTo和Driver)的就不要手動(dòng)綁定
3.一定要熟練RxSwift提供的操作符,要會(huì)自定義操作符


RxSwift的優(yōu)點(diǎn)

  • Composable 可組合蟀淮,在設(shè)計(jì)模式中有一種模式叫做組合模式最住,你可以方便的用不同的組合實(shí)現(xiàn)不同的類
  • Reusable 代碼可重用,原因很簡(jiǎn)單怠惶,對(duì)應(yīng)RxSwift涨缚,就是一堆Obserable
  • Declarative 響應(yīng)式的,因?yàn)闋顟B(tài)不可變策治,只有數(shù)據(jù)變化
  • Understandable and concise 簡(jiǎn)潔脓魏,容易理解。
  • Stable 穩(wěn)定通惫,因?yàn)?code>RxSwift寫出的代碼茂翔,單元測(cè)試時(shí)分方便
  • Less stateful“無(wú)”狀態(tài)性,因?yàn)閷?duì)于響應(yīng)式編程履腋,你的應(yīng)用程序就是一堆數(shù)據(jù)流
  • Without leaks 沒有泄漏珊燎,因?yàn)橘Y源管理非常簡(jiǎn)單

文章原址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市遵湖,隨后出現(xiàn)的幾起案子悔政,更是在濱河造成了極大的恐慌,老刑警劉巖延旧,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谋国,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡垄潮,警方通過查閱死者的電腦和手機(jī)烹卒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)弯洗,“玉大人,你說(shuō)我怎么就攤上這事逢勾∧嫡” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵溺拱,是天一觀的道長(zhǎng)逃贝。 經(jīng)常有香客問我谣辞,道長(zhǎng),這世上最難降的妖魔是什么沐扳? 我笑而不...
    開封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任泥从,我火速辦了婚禮,結(jié)果婚禮上沪摄,老公的妹妹穿的比我還像新娘躯嫉。我一直安慰自己,他們只是感情好杨拐,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開白布祈餐。 她就那樣靜靜地躺著,像睡著了一般哄陶。 火紅的嫁衣襯著肌膚如雪帆阳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天屋吨,我揣著相機(jī)與錄音蜒谤,去河邊找鬼。 笑死至扰,一個(gè)胖子當(dāng)著我的面吹牛鳍徽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播渊胸,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼旬盯,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了翎猛?” 一聲冷哼從身側(cè)響起胖翰,我...
    開封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎切厘,沒想到半個(gè)月后萨咳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡疫稿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年培他,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片遗座。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡舀凛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出途蒋,到底是詐尸還是另有隱情猛遍,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站懊烤,受9級(jí)特大地震影響梯醒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜腌紧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一茸习、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧壁肋,春花似錦号胚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至乙帮,卻和暖如春杜漠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背察净。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工驾茴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人氢卡。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓锈至,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親译秦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子峡捡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容