非同期コードの結合への移行
22000 ワード
ジャンプする前にステージを設定してください.
我々は動物の名前と2つのボタンを表示するセルのリストを示しています:動物の絵文字を表示し、他の動物の音を作るには、アプリケーションを持っているとしましょう.
任意の実世界のアプリと同じように、我々は、チーム上の誰もが自分の方法は最高だと思うように異なる実装されている同様の機能を持っている🤡
我々は見ることができるように、我々はこのアプリで非同期コードのいくつかの例があります.コミュニケーションのこれらのタイプの間で理解する1つの重要な違いは、我々が行っている「ネットワーク要求」がただ一つの結果を与えるだけであるということです.いずれかの成功に終わるだろうし、我々の配列を取得します
サーバがダウンしてエラーを送信した場合、1秒後には
我々の代わりにこれを見てみましょう
我々の背中
心に留めておく必要があるもう一つのことは
“ネットワーク要求”と我々のセルからのボタンタップの違いは、タップ/無限の数が含まれていることができます/値は、我々のボタンからストリームを渡されます.我々は複数の結果を操作しているとき/かどうかは、彼らが来るのを停止するかどうかわからない、我々は使用する必要があります
Unlike
では、我々の委任とコールバックコードを取り替えることによって、これを行動で見ましょう
私たちのコミュニケーションの2つの元のフォームを2つに置き換えながら
入れ子を作りましょう
更新時刻
結果を設定した スイッチング 私たちのアプリは、今までのように動作し続ける必要があります今、私たちの方法は最高です.
10 xエンジニアの地位へようこそ🙌🏽
コンバインはかなり滑らかであり、私たちの機会を単一のパターンにすべてのコミュニケーションパターンを統合するために提供しています.また、誰もが自分の母親は、反応性のフレームワークを使用しているので、同様にネイティブのIOSの開発のための標準になる可能性がありますので、最初のパーティのバージョンで快適になるかもしれません.
今すぐそこに行く、あなたの上司を説得するすべてのコードをリファクタリングする必要がありますので、情熱的に行う😘
我々は動物の名前と2つのボタンを表示するセルのリストを示しています:動物の絵文字を表示し、他の動物の音を作るには、アプリケーションを持っているとしましょう.
Designer was paid in equity 😛
任意の実世界のアプリと同じように、我々は、チーム上の誰もが自分の方法は最高だと思うように異なる実装されている同様の機能を持っている🤡
/// AnimalsViewController.swift
class AnimalsViewController: UITableViewController {
...
func getAnimals() {
NetworkingService.getAnimals { [weak self] (result) in
switch result {
case .success(let animals):
self?.animals = animals
self?.tableView.reloadData()
case .failure(let error):
print(error)
}
}
}
...
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
animalCell?.delegate = self
animalCell?.shouldMakeNoiseForAnimal = { [weak self] animal in
self?.makeNoise(for: animal)
}
...
}
...
}
extension AnimalsViewController: AnimalCellDelegate {
func shouldShowEmoji(for animal: Animal) {
showEmoji(for: animal)
}
}
このTableViewController
を返すAnimal
'サーバーからのSとユーザーが“絵文字”ボタンをクリックしたり、“make noise”ボタンをタップするときのロジックを実装./// NetworkService.swift
enum NetworkingService {
static func getAnimals(completion: @escaping (Result<[Animal], Error>) -> Void) {
let animals: [Animal] = [.dog, .cat, .frog, .panda, .lion]
completion(.success(animals))
}
}
ネットワークサービスを呼び出すときは、サーバーが戻ったときのコールバックとして機能するクロージャを渡しますAnimal
データ./// AnimalCell.swift
protocol AnimalCellDelegate: AnyObject {
func shouldShowEmoji(for animal: Animal)
}
class AnimalCell: UITableViewCell {
...
weak var delegate: AnimalCellDelegate?
var shouldMakeNoiseForAnimal: ((Animal) -> Void)?
@IBAction func didTapShowEmojiButton() {
delegate?.shouldShowEmoji(for: animal)
}
@IBAction func didTapMakeNoiseButton() {
shouldMakeNoiseForAnimal?(animal)
}
...
}
The AnimalCell
私たちには、同じことをする2つの異なる方法がありますパスAnimal
ボタンがタップされたときにオブジェクト.最初の方法はdidTapShowEmojiButton
デリゲートパターンを使用してAnimal
我々の目的AnimalsViewController
. もう一つはdidTapMakeNoiseButton
これは、動物を送るためにコールバックを使用していますAnimalsViewController
.我々は見ることができるように、我々はこのアプリで非同期コードのいくつかの例があります.コミュニケーションのこれらのタイプの間で理解する1つの重要な違いは、我々が行っている「ネットワーク要求」がただ一つの結果を与えるだけであるということです.いずれかの成功に終わるだろうし、我々の配列を取得します
Animal
'または、エラーを取得します.サーバがダウンしてエラーを送信した場合、1秒後には
Animal
's、それ以外の要求がなされるまで、習慣はそうしません.これらの状況では、単一の結果を返すことを期待しているだけで、我々はFuture
.未来
Future
の結果を返すように設計されているPromise
. エーPromise
は、Swift.Result
, いくつかのコントロールフローを書いてから、Promise
好きにするpromise(.success(myObject))
. Future
を初期化するPromise
閉鎖とそれから他のように扱われますPublisher
ここで、あなたはsink
値を取得するには我々の代わりにこれを見てみましょう
getAnimals
メソッドNetworkingService.swift
:... // enum NetworkingService {
static func getAnimals() -> Future<[Animal], Error> {
return Future { promise in
let animals: [Animal] = [.dog, .cat, .frog, .panda, .lion]
promise(.success(animals))
}
}
... // NetworkingService closing }
私たちの前の関数シグネチャとコールバックとの間にはたくさんの類似点がありますFuture
. 我々は、我々Future
を取る閉鎖によってPromise
, そして、我々はどちらかを通過success
またはfailure
私たちの約束に戻ると、正しい結果を返すことを決定したこの場合、success(animals)
.我々の背中
AnimalsViewController
関数シグネチャのエラーが発生しましたNetworkingService.getAnimals
変更.これらのエラーを修正するには、単にFuture
我々が他のものを扱うようにPublisher
....
var getAnimalsToken: AnyCancellable?
func getAnimals() {
getAnimalsToken = NetworkingService.getAnimals()
.sink(
receiveCompletion: { completion in
switch completion {
case .finished:
print("Subscription finished")
case .failure(let error):
print("Error getting animals -", error)
}
},
receiveValue: { [weak self] animals in
self?.animals = animals
self?.tableView.reloadData()
}
)
}
...
だから今私たちはsink
我々のためにFuture
Publisher
これは2つのクロージャにかかります.receiveCompletion
and receiveValue
. 使用するreceiveCompletion
サブスクリプションが終了したら、追加のロジックを行うだけでなく、発生した可能性のあるエラーを処理します.The receiveValue
ブロックは、単に期待値で渡すことによってより簡単です例ではAnimal
オブジェクト.心に留めておく必要があるもう一つのことは
sink
'我々が彼らに言及を保つならば、sは記憶から落ちます.そこは我々の小さな仲間getAnimalsToken
入る.通過
“ネットワーク要求”と我々のセルからのボタンタップの違いは、タップ/無限の数が含まれていることができます/値は、我々のボタンからストリームを渡されます.我々は複数の結果を操作しているとき/かどうかは、彼らが来るのを停止するかどうかわからない、我々は使用する必要があります
PassthroughSubject
. Unlike
Future
, the PassthroughSubject
サブスクリプションは、最初の結果が送信された後に終了しませんが、代わりに、その必要がありますCompletion<Failure>
手動でストリームを送信します.では、我々の委任とコールバックコードを取り替えることによって、これを行動で見ましょう
AnimalCell.swift
with PassthroughSubject
....
var showEmojiPublisher = PassthroughSubject<Animal, Never>()
var makeNoisePublisher = PassthroughSubject<Animal, Never>()
@IBAction func didTapShowEmojiButton() {
showEmojiPublisher.send(animal)
}
@IBAction func didTapMakeNoiseButton() {
makeNoisePublisher.send(animal)
}
...
それはかなり簡単なスワップです.私たちはdelegate
and shouldMakeNoiseForAnimal
プロパティPassthroughSubject
'sを通して購読できるssink
'コールサイトのS.その後、我々は単に送信Animal
それぞれを通してPublisher
いずれかのボタンをタップするたびに.私たちのコミュニケーションの2つの元のフォームを2つに置き換えながら
PassthroughSubject
'sは働くでしょう、我々が両方のために参照に掛かる必要があるので、それは理想より少ないですsink
'すべての細胞のs.彼らが同じタイプのものであることは、ちょっと臭いcuzでもありますPublisher
別の名前で.入れ子を作りましょう
Action
我々が送ることができるenumPublisher
まだそれぞれのときに何が起こるかについてのコンテキストを維持しながらAction
ダウンストリーム....
enum Action {
case showEmoji(Animal)
case makeNoise(Animal)
}
var actionPublisher = PassthroughSubject<Action, Never>()
...
@IBAction func didTapShowEmojiButton() {
actionPublisher.send(.showEmoji(animal))
}
@IBAction func didTapMakeNoiseButton() {
actionPublisher.send(.makeNoise(animal))
}
...
我々の新しいactionPublisher
発行するAnimalCell.Action
'sと現在、我々は1を持っているだけですsink
テーブルビューの各セルにハングアップする.更新時刻
cellForRowAt indexPath
インAnimalsViewController.swift
:...
// 1
var cellTokens = [IndexPath: AnyCancellable]()
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
// 2
cellTokens[indexPath] = animalCell?.actionPublisher
.sink { [weak self] action in
// 3
switch action {
case .showEmoji(let animal):
self?.showEmoji(for: animal)
case .makeNoise(let animal):
self?.makeNoise(for: animal)
}
}
...
}
...
cellTokens
私たちはそれぞれに参照を維持することができますsink
それで、それは生きていて、価値を観察することができます.sink
関連するIndexPath
. action
両方を扱うことができますAnimalCell.Action
'sは、我々の更新プログラムを更新するにはsink
's論理が我々を加えるならばAction
将来的に.10 xエンジニアの地位へようこそ🙌🏽
結論
コンバインはかなり滑らかであり、私たちの機会を単一のパターンにすべてのコミュニケーションパターンを統合するために提供しています.また、誰もが自分の母親は、反応性のフレームワークを使用しているので、同様にネイティブのIOSの開発のための標準になる可能性がありますので、最初のパーティのバージョンで快適になるかもしれません.
今すぐそこに行く、あなたの上司を説得するすべてのコードをリファクタリングする必要がありますので、情熱的に行う😘
Reference
この問題について(非同期コードの結合への移行), 我々は、より多くの情報をここで見つけました https://dev.to/kilo_loco/migrating-asynchronous-code-to-combine-1dnoテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol