知っておくべき6つのSwiftCombineオペレーター

記事の翻訳は、上級コース「iOSDeveloper」の開始を見越して作成されました








この記事では、6つの便利なCombine演算子について説明します。Xcode Playgroundでそれぞれを実験しながら、例を使用してこれを行います。



ソースコードは記事の最後にあります。



さて、それ以上の苦労なしに、始めましょう。



1.追加



このステートメントのグループにより、イベント、値、またはその他の発行元を元の発行元に追加(文字通り「追加」)することができます。



import Foundation
import Combine

var subscriptions = Set<AnyCancellable>()

func prependOutputExample() {
    let stringPublisher = ["World!"].publisher
    
    stringPublisher
        .prepend("Hello")
        .sink(receiveValue: { print($0) })
        .store(in: &subscriptions)
}


結果:HelloおよびWorld順番に出力され







ます次に、同じタイプの別のパブリッシャーを追加しましょう:



func prependPublisherExample() {
    let subject = PassthroughSubject<String, Never>()
    let stringPublisher = ["Break things!"].publisher
    
    stringPublisher
        .prepend(subject)
        .sink(receiveValue: { print($0) })
        .store(in: &subscriptions)
    
    subject.send("Run code")
    subject.send(completion: .finished)
}


結果は前の結果と同様です(.finishedオペレーターが.prepend機能するには、サブジェクトにイベント送信する必要があることに注意してください)。







2.追加



演算子.append(文字通り「最後に追加」)も同様.prependに機能しますが、この場合、元の発行元に値を追加します:



func appendOutputExample() {
    let stringPublisher = ["Hello"].publisher
    
    stringPublisher
        .append("World!")
        .sink(receiveValue: { print($0) })
        .store(in: &subscriptions)
}


その結果、私たちは見HelloWorldコンソールに出力:







以前.prependに別のPublisheraを追加するために使用したものと同様に、オペレーター用にこのオプションもあります.append







3.switchToLatest



より複雑な演算子を.switchToLatest使用すると、一連のパブリッシャーを1つのイベントストリームに結合できます。



func switchToLatestExample() {
    let stringSubject1 = PassthroughSubject<String, Never>()
    let stringSubject2 = PassthroughSubject<String, Never>()
    let stringSubject3 = PassthroughSubject<String, Never>()
    
    let subjects = PassthroughSubject<PassthroughSubject<String, Never>, Never>()
    
    subjects
        .switchToLatest()
        .sink(receiveValue: { print($0) })
        .store(in: &subscriptions)
    
    subjects.send(stringSubject1)
    
    stringSubject1.send("A")
    
    subjects.send(stringSubject2)
    
    stringSubject1.send("B") // 
    
    stringSubject2.send("C")
    stringSubject2.send("D")
    
    subjects.send(stringSubject3)
    
    stringSubject2.send("E") // 
    stringSubject2.send("F") // 
    
    stringSubject3.send("G")
    
    stringSubject3.send(completion: .finished)
}


コードで行われていることは次のとおりです。



  • PassthroughSubject値を送信する3つのオブジェクトを作成します。
  • PassthroughSubject他のオブジェクトをディスパッチするメインオブジェクトを作成しますPassthroughSubject
  • stringSubject1本題に発送いたします。
  • stringSubject1 値Aを取得します。
  • 私たちは、派遣stringSubject2自動的stringSubject1イベントを破棄、主被写体に。
  • 同様に、値をに送信しstringSubject2、接続して、stringSubject3完了イベントをディスパッチします。


結果が出力されACDG







簡単にするために、関数はisAvailableランダムな値を返すBoolいくつかの遅延後。



func switchToLatestExample2() {
    func isAvailable(query: String) -> Future<Bool, Never> {
        return Future { promise in
            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                promise(.success(Bool.random()))
            }
        }
    }
    
    let searchSubject = PassthroughSubject<String, Never>()
    
    searchSubject
        .print("subject")
        .map { isAvailable(query: $0) }
        .print("search")
        .switchToLatest()
        .sink(receiveValue: { print($0) })
        .store(in: &subscriptions)
    
    searchSubject.send("Query 1")
    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
        searchSubject.send( "Query 2")
    }
}


オペレーターのおかげで、.switchToLatest私たちは私たちが望むことを達成します。1つのBool値のみが表示されます。







4.マージ(:)



1つだけから値を取得しているかのように.merge(with:)2つを組み合わせる ために使用Publishersます:



func mergeWithExample() {
    let stringSubject1 = PassthroughSubject<String, Never>()
    let stringSubject2 = PassthroughSubject<String, Never>()
    
    stringSubject1
        .merge(with: stringSubject2)
        .sink(receiveValue: { print($0) })
        .store(in: &subscriptions)
    
    stringSubject1.send("A")
    
    stringSubject2.send("B")
    
    stringSubject2.send("C")
    
    stringSubject1.send("D")
}


結果は、要素の交互のシーケンスです。







5.combineLatest



オペレーター.combineLatestは、各パブリッシャーの最新の値を含むタプルを公開します。



これを説明するために、次の実際の例を考えてみましょう。ユーザー名、パスワード、UITextFieldsおよび続行ボタンがあります。ユーザー名が5文字以上、パスワードが8文字以上になるまで、ボタンを無効にしておく必要があります。これは、演算子を使用して簡単に実現できます.combineLatest



func combineLatestExample() {
    let usernameTextField = CurrentValueSubject<String, Never>("")
    let passwordTextField = CurrentValueSubject<String, Never>("")
    
    let isButtonEnabled = CurrentValueSubject<Bool, Never>(false)
    
    usernameTextField
        .combineLatest(passwordTextField)
        .handleEvents(receiveOutput: { (username, password) in
            print("Username: \(username), password: \(password)")
            let isSatisfied = username.count >= 5 && password.count >= 8
            isButtonEnabled.send(isSatisfied)
        })
        .sink(receiveValue: { _ in })
        .store(in: &subscriptions)
    
    isButtonEnabled
        .sink { print("isButtonEnabled: \($0)") }
        .store(in: &subscriptions)
    
    usernameTextField.send("user")
    usernameTextField.send("user12")
    
    passwordTextField.send("12")
    passwordTextField.send("12345678")
}


一旦usernameTextField 及びpasswordTextField受信user12、及び12345678従って、条件が満たされ、そしてボタンが活性化されます。







6.zip



オペレーター.zipは、各パブリッシャーから一致する値のペアを提供します。両方の発行者が同じ値を発行したかどうかを判断したいとしますInt



func zipExample() {
    let intSubject1 = PassthroughSubject<Int, Never>()
    let intSubject2 = PassthroughSubject<Int, Never>()
    
    let foundIdenticalPairSubject = PassthroughSubject<Bool, Never>()
    
    intSubject1
        .zip(intSubject2)
        .handleEvents(receiveOutput: { (value1, value2) in
            print("value1: \(value1), value2: \(value2)")
            let isIdentical = value1 == value2
            foundIdenticalPairSubject.send(isIdentical)
        })
        .sink(receiveValue: { _ in })
        .store(in: &subscriptions)
    
    foundIdenticalPairSubject
        .sink(receiveValue: { print("is identical: \($0)") })
        .store(in: &subscriptions)
    
    intSubject1.send(0)
    intSubject1.send(1)
    
    intSubject2.send(4)
    
    intSubject1.send(6)
    intSubject2.send(1)
    intSubject2.send(7)
    
    intSubject2.send(9) //  ,       
}


fromintSubject1から次の対応する値がありintSubject2ます:



  • 0と4
  • 1と1
  • 6と7


対応する値がまだ公開されていない9ため、 後者の値は表示されintSubject1ません。







リソース



ソースコードはGistで入手できます



結論



他のタイプのCombine演算子に興味がありますか?私の他の記事を自由に訪問してください:






All Articles