Combineを軽く触ってみて
どうも初めましてtikingです。
Aizu Advent Calendar 2019の17日目を担当しています。
地方の大学でB2しています。Swiftはまだまだ初心者なのでみなさん暖かい目で見守ってください。
今回は、MVVM with Combineチュートリアル for iOSを通して学べたことをOutPutできたらと思い記事を書かせていただきました。
Combine is 何?
CombineとはApple発のUIイベント、ネットワーク通信などが非同期に提供するデータを処理するためのFrameworkです。
何ができるん??
例えば、文字の入力制限にも使うことができます。
その他、いろいろ応用できます。
構成要素と役割
・Publisher → データを生成
・Subscriber → データを受け取る
・Operator → データの加工をする
・Subscription → PublisherとSubscriberのコネクションを表す。
の4つです。
それぞれの構成要素の説明
Publisher
・Output, Failureの定義が書いてある
→成功時のデータの型と、失敗時のデータの型を定義してあげる。
・receive(subscriber:)の実装
→Publisherプロトコルの必須メソッドreceive(subscriber:)を実装します。
このメソッドはsubscriberによってsubscribeされた時に呼ばれます。
###つまり、このメソッドは、自分的にはイベントの発行を担当している部分かなと思っております。
Subscriber
・定義ではprotocolで定義されていた。
・sink(receiveCompletion:receiveValue :)は、イベントの完了状態を受け取り、任意のクロージャに書かれた処理を実行してくれます。
・assign(to: on: )
これは、toに割り当てるプロパティをKey-Chainで渡してあげたら大丈夫です。
onにはプロパティを含むオブジェクトを渡してあげたら大丈夫です。
つまり、このメソッドは関係の変化を説明するライフサイクルイベントを表現する場所となります。
Operator
こちらに関しては理解がまだまだ甘いので、簡単な二つだけをしょうかいします
・Prepend
あるPublisherの前に値が出力されるようにPublisherを挿入します。
・Append
Prependとは反対に対象のPublisherの後に値を出力します。
###つまり、このメソッドは、受けとった値を加工したいときに使います。
DEMO
DEMO.1
こちらは、PublisherとSubscriberの簡単な通信を行っているものです。
import Foundation
import Combine
enum WeatherError : Error {
case thingsJustHappen
}
let Publisher = PassthroughSubject<Int, WeatherError>()
let subscriber = Publisher
.filter{$0 > 25}
.sink(receiveCompletion: {_ in}, receiveValue: {print("reseive value is \($0)")})
let anotherSubscriber = Publisher.handleEvents(receiveSubscription: {Subscription in print("New Subscription is \(Subscription)")},
receiveOutput: {output in print("New Value output is \(output)")}, receiveCompletion: {error in print("Subscription completed with potential error is \(error)")},
receiveCancel: {print("Subscription Canseled")})
.sink(receiveCompletion: {_ in}, receiveValue: {print("reseive value is \($0)")})
Publisher.send(30)
Publisher.send(20)
Publisher.send(completion: Subscribers.Completion<WeatherError>.failure(.thingsJustHappen))
Publisher.send(100)
Output
こちらは、Errorを受けっとたら終了する処理
receiveCompletion: {error in print("Subscription completed with potential error is (error)")}にて、やっているのでそれ以降は通信されなくなってます。
New Subscription is PassthroughSubject
reseive value is 30
New Value output is 30
reseive value is 30
New Value output is 20
reseive value is 20
Subscription completed with potential error is failure(__lldb_expr_1.WeatherError.thingsJustHappen)
DEMO.2
こちらは、時間で文字が入力された文字が消える実装をかいたものです。
こちらの例では5文字を超えたら消えるようにしています。
import SwiftUI
import Combine
struct ContentView: View {
@ObservedObject private var inputchar = RestrictInput(5)
var body: some View {
Form{
TextField("input text", text: $inputchar.text)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
Text("入力されたのは、\(inputchar.text)")
}
}
}
//文字を規定数入力すると消してくれるクラス
class RestrictInput: ObservableObject {
@Published var text = ""
private var canc: AnyCancellable!
init (_ maxLength: Int) {
canc = $text
.debounce(for: 1, scheduler: DispatchQueue.main)
.map { String($0.prefix(maxLength)) }
.assign(to: \.text, on: self)
}
deinit {
canc.cancel()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
参考にさせていただいた記事
#keyPathとKeyPath
[Swift] はじめてのCombine | Apple製の非同期フレームワークを使ってみよう
Apple公式Subscriber
【iOS】Combineフレームワークまとめ
Apple公式sink
まとめ
自分もまだまだ勉強不足なところもあり、わかりにくい点もあったかもしれませんがここまで読んでいただきありがとうございます。
間違っているところなどありましたら、教えていただけると幸いです。
これからも勉強の方を頑張っていこうと思いますのでよろしくお願いします。