Reactivecocoa 5.0入門指北

什么是RAC?

幾乎每一篇介紹RAC的文章開頭都是這么一個問題。我這篇文章是寫給新手(包括我自己)看的,所以這個問題更是無法忽視。
簡單的說,RAC就是一個第三方庫,他可以大大簡化你的代碼過程。
官方的說,ReactiveCocoa(其簡稱為RAC)是由GitHub開源的一個應用于iOS和OS X開發的新框架。RAC具有函數式編程和響應式編程的特性。

為什么我們要學習RAC?

為了提高我們的開發效率。RAC在某些特定情況下開發時可以大大簡化代碼,并且目前來看安全可靠。

學習背景

趁著過年前的激情,準備入坑RAC Swift的版本,在RAC 5.0這個版本,作者做了一個很大的改版,API已經重新命名。對于我個人而言,網上可以學習和參考的資源是很少的,新學一點東西都要花時間去慢慢的研讀,然后整理自己的筆記。原來 RAC 中只和 Swift 平臺相關的核心代碼被單獨抽取成了一個新框架:ReactiveSwift 。Swift 正在快速成長并且成長為一個跨平臺的語言。把只和 Swift 相關的代碼抽取出來后,ReactiveSwift 就可以在其他平臺上被使用,而不只是局限在 CocoaTouch 和 Cocoa 中。

轉換的類型有:

  • RACSignal 和 SignalProducer、 Signal
  • RACCommand 和 Action
  • RACScheduler 和 SchedulerType
  • RACDisposable 和 Disposable

簡介

需使用的頭文件

import ReactiveCocoa
import Result
import ReactiveSwift

  • (值得注意的是Signal 依賴于ReactiveSwift )
  • (NoError 依賴于 Result)

主要的類型

  • 1.事件(Event)
  • 2.監聽器(Observer)
  • 3.存根(Disposable)
  • 4.信號(Signal

主要用法

1.信號的創建

// MARK: - 0.創建信號的方法
    func createSignalMehods() {
        // 1.通過信號發生器創建(冷信號)
        let producer = SignalProducer<String, NoError>.init { (observer, _) in
            print("新的訂閱,啟動操作")
            observer.send(value: "Hello")
            observer.send(value: "World")
        }
        
        let subscriber1 = Observer<String, NoError>(value: { print("觀察者1接收到值 \($0)") })
        let subscriber2 = Observer<String, NoError>(value: { print("觀察者2接收到值 \($0)") })
        
        print("觀察者1訂閱信號發生器")
        producer.start(subscriber1)
        print("觀察者2訂閱信號發生器")
        producer.start(subscriber2)
        //注意:發生器將再次啟動工作
        
        // 2.通過管道創建(熱信號)
        let (signalA, observerA) = Signal<String, NoError>.pipe()
        let (signalB, observerB) = Signal<String, NoError>.pipe()
        Signal.combineLatest(signalA, signalB).observeValues { (value) in
            print( "收到的值\(value.0) + \(value.1)")
        }
        observerA.send(value: "1")
        observerA.sendCompleted()
        observerB.send(value: "2")
        observerB.sendCompleted()
    }

2.文本輸入框的監聽

// MARK: - 1.監聽輸入框輸入
    func testTF() {
        // 輸入時監聽
        userNameTF.reactive.continuousTextValues.observeValues { text in
            print(text ?? "")
        }
        
        // 監聽粘貼進來的文本
        let result = userNameTF.reactive.values(forKeyPath: "text")
        result.start { (text) in
            print(text)
        }
        
    }

3.按鈕監聽

// MARK: - 3.按鈕監聽
    func testBtnClick() {
        testBtn.reactive.trigger(for: .touchUpInside).observeValues {
           print("按鈕點擊")
        }
    }

4.信號合并

// MARK: - 4.信號聯合
    func testCombineLatest() {
        
        // 通過管道創建
        let (signalA, observerA) = Signal<String, NoError>.pipe()
        let (signalB, observerB) = Signal<String, NoError>.pipe()
        Signal.combineLatest(signalA, signalB).observeValues { (value) in
            print( "收到的值\(value.0) + \(value.1)")
        }
        observerA.send(value: "1")
        observerA.sendCompleted()
        observerB.send(value: "2")
        observerB.sendCompleted()
        
        
    }
    // MARK: - 5.信號聯合
    func testZip() {
        let (signalA, observerA) = Signal<String, NoError>.pipe()
        let (signalB, observerB) = Signal<String, NoError>.pipe()
        
        Signal.zip(signalA, signalB).observeValues { (value) in
            print( "收到的值\(value.0) + \(value.1)")
        }
        
        signalA.zip(with: signalB).observeValues { (value) in
            
        }
        observerA.send(value: "1")
        observerA.sendCompleted()
        observerB.send(value: "2")
        observerB.sendCompleted()
        
    }

5.Scheduler調度器

    // MARK: - 6.Scheduler(調度器)
    func testScheduler() {
        // 主線程上延時0.3秒調用
        QueueScheduler.main.schedule(after: Date.init(timeIntervalSinceNow: 0.3)) {
            print("主線程調用")
        }
        
        QueueScheduler.init().schedule(after: Date.init(timeIntervalSinceNow: 0.3)){
            print("子線程調用")
        }
        
    }

6.Delegate

    let (signal, obser) = Signal<Any, NoError>.pipe()
    @IBAction func btnClick(btn: UIButton) {
        obser.send(value: "代理測試")
    }
    // MARK: - 7.Delegate
    func testDelegate() {
        redView.signal.observeValues { (value) in
            print("按鈕點擊\(value)")
        }
    }

7.通知

// MARK: - 8.通知
    func testNoti() {
     // 普通的通知方法
       NotificationCenter.default.reactive.notifications(forName: Notification.Name(rawValue: "home")).observeValues { (value) in
            print(value.object ?? "")
        }
        
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "home"), object: nil)
        
        // 鍵盤的通知
        NotificationCenter.default.reactive.notifications(forName: Notification.Name(rawValue: "UIKeyboardWillShowNotification" ), object: nil).observeValues { (value) in
            print("鍵盤彈起")
        }
        NotificationCenter.default.reactive.notifications(forName: Notification.Name(rawValue: "UIKeyboardWillHideNotification"), object: nil).observeValues { (value) in
            print("鍵盤收起")
        }
    }

8.KVO

    // MARK: - 9.KVO
    func testKVO() {
        let result = self.view.reactive.values(forKeyPath: "bounds")
        result.start { [weak self](rect) in
            print(self?.view ?? "")
            print(rect)
        }
    }

9.迭代器

// MARK: - 10.迭代器
    func testIterator() {
        
        // 數組的迭代器
        let array:[String] = ["name","name2"]
        var arrayIterator =  array.makeIterator()
        while let temp = arrayIterator.next() {
            print(temp)
        }
        
        // swift 系統自帶的遍歷
        array.forEach { (value) in
            print(value)
        }
        
        // 字典的迭代器
        let dict:[String: String] = ["key":"name", "key1":"name1"]
        var dictIterator =  dict.makeIterator()
        while let temp = dictIterator.next() {
            print(temp)
        }
        
        // swift 系統自帶的遍歷
        dict.forEach { (key, value) in
            print("\(key) + \(value)")
        }
    
    }

10 、其他事件綁定

      // UI綁定到Model  
       Signal.combineLatest(uerNameTF1.reactive.continuousTextValues,passwordTF1.reactive.continuousTextValues).observeValues { (name, password) in
            //print("name = \(name) + password = \(password)")
        }
        
        // 當輸入框的兩個值長度都大于或者等于6,按鈕才可以點擊
        Signal.combineLatest(uerNameTF1.reactive.continuousTextValues,passwordTF1.reactive.continuousTextValues).map { (name, password) -> Bool in
            return ((name?.characters.count)! >= 6 && (password?.characters.count)! >= 6)
        }.observeValues { [weak self](value) in
            print("合并\(value)")
            self?.loginBtn.isEnabled = value
        }

        // 參數省略        
        Signal.combineLatest(uerNameTF1.reactive.continuousTextValues,passwordTF1.reactive.continuousTextValues).map { $0?.characters.count ?? 0 >= 6 && $1?.characters.count ?? 0 >= 6
            }.observeValues { [weak self](value) in
                print("合并\(value)")
                self?.loginBtn.isEnabled = value
        }
        
        loginBtn.reactive.isEnabled <~ Signal.combineLatest(uerNameTF1.reactive.continuousTextValues,passwordTF1.reactive.continuousTextValues).map { $0?.characters.count ?? 0 >= 6 && $1?.characters.count ?? 0 >= 6
        }
 
*****
class ViewModel {
    var username: MutableProperty<String>
    var password: MutableProperty<String>
    var loginEnabled: Property<Bool>

    // This can be done in a different spot, or init can be made to take initial values as parameters, or whatever...
    init() {
        userName = MutableProperty("")
        password = MutableProperty("")

        // I'm pretty sure the below code is incorrect, but I'm sure you get the idea that we're creating a "calculated, read-only property" out of the above two.
        loginEnabled = .combineLatest(userName.producer, password.producer).map { $0.0.characters.count > 0 && $0.1.characters.count > 0 }
    }
} 
*****
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,963評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,348評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,083評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,706評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,442評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,802評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,795評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,983評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,542評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,287評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,486評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,030評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,710評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,116評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,412評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,224評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,462評論 2 378

推薦閱讀更多精彩內容