Combineを軽く触ってみて



# Combineを軽く触ってみて
どうも初めまして[tiking](https://twitter.com/tikin0716)です。
[Aizu Advent Calendar 2019](https://adventar.org/calendars/3938)の17日目を担当しています。
地方の大学でB2しています。Swiftはまだまだ初心者なのでみなさん暖かい目で見守ってください。

今回は、[MVVM with Combineチュートリアル for iOS](https://qiita.com/you_matz/items/a3d640be2a8feaf698bd)を通して学べたことをOutPutできたらと思い記事を書かせていただきました。


# Combine is 何？
CombineとはApple発のUIイベント、ネットワーク通信などが非同期に提供するデータを処理するためのFrameworkです。
# 何ができるん？？
例えば、文字の入力制限にも使うことができます。
その他、いろいろ応用できます。


# 構成要素と役割
・Publisher →　データを生成
・Subscriber → データを受け取る
・Operator → データの加工をする
・Subscription → PublisherとSubscriberのコネクションを表す。
の４つです。

関係図はこんな感じ
**![](https://lh4.googleusercontent.com/otj6jWbwZWvJEqB8vh6456h6R4LzUGvitQfMgmbE9pDPT5erRhDiH8O8p9-3dZ7rqzdS_mgNhDA3ZFf6yWlHs1zEwaJFLiRT7Bxh_bCoc7tpGlWzMs6KE2xR2IsQhDcEbVhnuMviWn4)**



# それぞれの構成要素の説明
## Publisher
・Output, Failureの定義が書いてある
→成功時のデータの型と、失敗時のデータの型を定義してあげる。

・receive(subscriber:)の実装
→Publisherプロトコルの必須メソッドreceive(subscriber:)を実装します。
　このメソッドはsubscriberによってsubscribeされた時に呼ばれます。


###つまり、このメソッドは、自分的にはイベントの発行を担当している部分かなと思っております。

## Subscriber

・定義ではprotocolで定義されていた。

・sink(receiveCompletion：receiveValue :)は、イベントの完了状態を受け取り、任意のクロージャに書かれた処理を実行してくれます。

・assign(to: on: )
これは、toに割り当てるプロパティを[Key-Chain](https://qiita.com/_tid_/items/6d44d0e91d2d02d0cfaa)で渡してあげたら大丈夫です。
onにはプロパティを含むオブジェクトを渡してあげたら大丈夫です。


### つまり、このメソッドは関係の変化を説明するライフサイクルイベントを表現する場所となります。

## Operator
こちらに関しては理解がまだまだ甘いので、簡単な二つだけをしょうかいします
・Prepend
あるPublisherの前に値が出力されるようにPublisherを挿入します。

・Append
Prependとは反対に対象のPublisherの後に値を出力します。

###つまり、このメソッドは、受けとった値を加工したいときに使います。



## DEMO
### DEMO.1
こちらは、PublisherとSubscriberの簡単な通信を行っているものです。

```swift

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文字を超えたら消えるようにしています。

```swift
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()
    }
}
```
![result](https://j.gifs.com/wVxGrX.gif)


# 参考にさせていただいた記事
[#keyPathとKeyPath](https://qiita.com/_tid_/items/6d44d0e91d2d02d0cfaa)
[[Swift] はじめてのCombine | Apple製の非同期フレームワークを使ってみよう](https://dev.classmethod.jp/smartphone/swift-combine-framework-for-beginners/)
[Apple公式Subscriber](https://developer.apple.com/documentation/combine/subscriber)
[【iOS】Combineフレームワークまとめ](https://qiita.com/shiz/items/5efac86479db77a52ccc)
[Apple公式sink](https://developer.apple.com/documentation/combine/publisher/3343978-sink)

# まとめ
自分もまだまだ勉強不足なところもあり、わかりにくい点もあったかもしれませんがここまで読んでいただきありがとうございます。
間違っているところなどありましたら、教えていただけると幸いです。
これからも勉強の方を頑張っていこうと思いますのでよろしくお願いします。