RxBluetoothKitでスキャンする

RxBluetoothKitでデバイスのスキャンを行おうとしたのですが、RxSwiftの知識0で挑んでボコボコにされました。

実行バージョン

RxBluetoothKit: 5.1.2

Swift: 4.2.1

ハマりポイント

公式チュートリアルページにペリフェラルへのスキャン方法についてこのようなコードが書いてあります。

manager.scanForPeripherals(withServices: serviceIds)
    .subscribe(onNext: { scannedPeripheral in
        let advertisementData = scannedPeripheral.advertisementData
    })

最初に試したのはこれを完全に真似してマネージャを作成して公式のコードそのままに書けばスキャンができると思っていたのですが、そんなことはなく、

ネット上にあるRxBluetoothKitの記事が古いものばかりで参考にできませんでした。

ダメな例

let manager:CentralManager(queue: .main, options: nil)
manager.scanForPeripherals(withServices: serviceIds)
    .subscribe(onNext: { scannedPeripheral in
        let advertisementData = scannedPeripheral.advertisementData
    })

optionsに指定していないので全てのペリフェラルを検出するはずでした!私の頭の中では…

問題点

このコードの問題点はCentralManagerのstateの確認ができていなかったことです。

 公式チュートリアル2章にStateの取得方法がしっかり書いてありました。

let disposable = manager.observeState()
     .startWith(state)
     .filter { $0 == .poweredOn }

RxSwiftがわかっていればそのままくっつけられるのでしょうがRxの知識0だったので全くわかりませんでした。

スキャン取得のコード

Rxを少し勉強して無事、スキャンすることができました。

間違っていないかは不明ですが、私の予想でコメントを書いておきました。イメージは間違っていないと思います。

    override func viewDidLoad() {
        super.viewDidLoad()
        myManager = CentralManager(queue: .main, options: nil)
        
        let scanDisposable = myManager.observeState()
            //始める前に引数を持たせておく
            .startWith(myManager.state)
            //セントラルが.powerdOn以外は弾く
            .filter{ $0 == .poweredOn }
            //ペリフェラルをスキャンする
            .flatMap({ (_) -> Observable<ScannedPeripheral> in
                return self.myManager.scanForPeripherals(withServices: nil)
            })
            //接続など処理を行う場所!
            .subscribe(onNext: { scannedPeripheral in
                print("ペリフェラル発見!")
            })
    }

CoreBluetoothでメソッドを呼んで呼んでの繰り返しだった部分が.演算子で次に渡せるようになっているので読む人は見やすいかなと思います。

Rx慣れていないと書くの大変です