Combineをどうしても理解したいということで、、、part1

## どうしてCombineを学びたいと思ったのか？
一番最初に作ったアプリで、MVVMアーキテクチャを使用し、１View1ViewMdoelへ書き換えたいという場面がありました。ここで問題になったのが、二つのViewModelで同じ値を保持させたいということです(値の変化も検知し、Viewへ反映させる)。その際に、`assgin(to:)`というメソッドを使った書き方を教えていただき、やりたいことが達成できました。その経験から『Combineの一部の機能だけでこんなできちゃうの？めちゃくちゃ便利やん？』と思ったのが、勉強に至った経緯です。現在チーム開発も行っており、将来的にも役に立つかなと思っています。

## 流れ
1. Combineとは？
1. 今回のキーワード
1. 値を流し、受け取り、ルールを定義してみる！
1. サブスクライバーの登録を無効にする
1. 片方のサブスクライバーの登録を無効化する
1. 複数のサブスクライバーの登録を一気解除する
1. まとめ

## Combineとは？

公式の一部を引用させてもらいました。
>イベント処理演算子を組み合わせて、非同期イベントの処理をカスタマイズする。Combine フレームワークは、時間の経過とともに値を処理するための宣言型 Swift APIを提供します。これらの値は、**さまざまな種類の非同期イベント**を表すことができます。Combine は、パブリッシャーが時間の経過とともに変化する可能性のある値を公開し、**サブスクライバー**が**パブリッシャー**からそれらの値を受け取ることを宣言します。

https://developer.apple.com/documentation/combine



今回ポイントとなるところが、 **『サブスクライバー(Subscriber)』** と **『パブリッシャー(Publisher)』** です。
ざっくり説明すると、値を流すのが、**パブリッシャー**で、流された値を受け取るのが**サブスクライバー**です。僕は下の図のようなイメージを持っています。電波塔は誰が聞くかかわからない放送を流します（パブリッシャーの役割）。その放送を聴きたい時はラジオのチューナーを合わせて聴く（サブスクライバーの役割）と言った感じです。
サブスクライバーについて補足です。パブリッシャーに対して、登録の処理を行うオブジェクトを指します。例えば、`sink()`で処理の登録を行なったプロパティを指すと言った感じです。
値を流すものを`ストリーム`や`管`と言ったりもするそうです。僕は管がイメージしやすかったので、今回は管を用いて説明させていただきます。

<img width="400" alt="combine1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3232025/bc261caf-23f6-a1ae-c00c-2f88915a4a82.png">

## 今回のキーワード
『`PassthroughSubject<Output,Failure>()`』
『`sink()`』
『`send()`』
『`cancel()`』
『`AnyCancellable型`』

## 値を流し、受け取り、ルールを定義してみる！

パブリッシャー・・・`PassthroughSubject<Int,Never>()`
サブスクライバー・・・`sink()`で登録を行なったsubjectA

``` swift
import Combine //🟥Combineフレームワークをインポートする。

let subject = PassthroughSubject<Int,Never>()//🟦値を流すための　管を作る

let subjectA = subject.sink { num in //🟦ルールを定義する。
    print("PassthroughSubjectgaが受け取った値は：\(num)")
}

subject.send(1) //🟦管に値を流し込む
subject.send(2)
subject.send(3)
```
『`PassthroughSubject<Int,Never>()`』は**管**のような役割を持っています。今回の場合は、Int型を受け取り、Int型を出力します。第二引数部分はエラーが起こらないNever型になっています。これに対して、『`.send()`』を使って**管**に値を送ります。その送られてきた値をどのように処理するのかを『`sink()`』のクロージャ内で定義しています。ここから、いろいろ変化していきます！！！

上の例で出てきたPassthroughSubjectはSubjectプロトコルに適合しているのですが、SubjectプロトコルもPublisherプロトコルを併せ持っているので、Pubisherと同様の働きをすることが可能です。そしてもう一つ。PassthroughSubjectと似た


https://developer.apple.com/documentation/combine/subject

## サブスクライバーの登録を無効にする
sink()のクロージャの中で行っていた処理の登録を無効にさせます。
```swift
let subject = PassthroughSubject<Int,Never>()

let subjectA = subject.sink { number in
    print("subjectA：",number)
}

subject.send(1)// A 1
subjectA.cancel()
subject.send(2)// 出力されない
subject.send(3)// 出力されない
```
ここで登場するのが『`cancel`』メソッドです。このcancelメソッドが、どうして値の流れを止めることができるのか説明します。まず、『sink』メソッドの返り値をドキュメントで確認すると、『`AnyCancellable型`』になっています。このAnyCancellable型はcancelメソッドを持っており、これを実行すると、値の流れを止めることができます。
今回の場合はsubjectAがcancelメソッドをsend(2)の直前で実行したため、subjectAに対して、send(2),send(3)を送ったとしても、sinkメソッドの処理が走らなかったというわけです。

## 片方のサブスクライバーの登録を無効化する

値の流れを二つの箇所で受け取りたいとし、尚且つ、subjectAに対しては途中で処理を無効化させたいときのサンプルコードです。

```swift
let subject = PassthroughSubject<Int,Never>()

let subjectA = subject.sink { number in
    print("subjectA：",number)
}

let subjectB = subject.sink { number in
    print("subjectB：",number)
}

subject.send(1)// B 1,A 1
subjectA.cancel()
subject.send(2)//B 2
subject.send(3)//B 3
```
subjectBでは全ての値を受け取り、subjectAではsend(1)以降のルールを行いたくないと言った場合です。sendで1が送られた後に、subjectAに登録の解除をさせます。

## 複数のサブスクライバーの登録を一気解除する
#### Set型のプロパティに追加
一つ一つキャンセルしてもいいですが、それが５０個、１００個と多くなっていくとさすがに骨が折れますよね。
なので、配列にAnyCancellable型の要素を追加していき、一気にcancelを実行すると楽にできそうです。しかし、ここで配列には追加していく要素は、キャンセルするために追加していくものなので、重複する意味はありません。（クリーニングのチケットを２枚もらっても、戻ってくる服は一枚しかない。みたいなイメージです。２枚もらう意味はあまりありませんよね。）この重複を避けるために使われるのが**Set型**です。重複した要素を自動で弾いてくれます。
＊Set型に追加したい場合はinsertで要素を追加していきます。

#### forEachで取り出しキャンセル
setプロパティに追加された要素を**forEach**を使用して順次取り出し、キャンセルしていきます。

```swift
var set = Set<AnyCancellable>()
let subject = PassthroughSubject<Int,Never>()


let subjectA = subject.sink { number in
    print("A",number)
}

let subjectB = subject.sink { number in
    print("B",number)
}

let subjectC = subject.sink { number in
    print("C",number)
}

set.insert(subjectA)
set.insert(subjectB)
set.insert(subjectC)
set.count  //🟦３つのサブスクライバーが入っている状態
subject.send(10)
subject.send(20)
subject.send(30)
set.forEach{
    $0.cancel() //🟦一気に登録を解除する
}
subject.send(40) //出力されない

実行結果-------＊順番は固定されていません。
C 10
A 10
B 10
C 20
A 20
B 20
C 30
A 30
B 30
```

## まとめ
1. 値を流す（パブリッシャー）
1. 登録された値の処理が書かれたオブジェクト（サブスクライバー）
1. 登録の解除（cancel）

上の３つについて説明させてもらいました。次回は`@Published`やオペレーターについてアウトプットしていきたいと思います！
間違っている箇所があれば、教えていただけると大変嬉しいですのでよろしくお願いします！