web-dev-qa-db-ja.com

あらゆる場所でAnyPublisher / eraseToAnyPublisherを使用しないようにする方法はありますか?

Combineの使い方を学んでいるところです。私はRx(RxSwiftとRxJava)の経験があり、非常に似ていることに気づいています。

ただし、まったく異なる(そして一種の煩わしい)ことの1つは、PublisherプロトコルがそのOutputおよびFailureタイプにジェネリックを使用しないことです。代わりに、関連する型を使用します。

これは、多形のPublisher型(_Publisher<Int, Error>_など)を指定して、それらの型でPublisherに準拠する型を単純に返すことができないことを意味します。代わりに_AnyPublisher<Int, Error>_を使用する必要があり、eraseToAnyPublisher()をすべての場所に含める必要があります。

これが唯一の選択肢であるなら、私はそれに耐えます。しかし、最近、Swiftの不透明型についても学びました。これを回避するためにそれらを使用できるかどうか疑問に思っています。

たとえば、_some Publisher_を返し、OutputおよびFailureに特定の型を使用する関数を用意する方法はありますか?

これは不透明型の完璧なケースのようですが、不透明型を使用して関連する型を指定する方法があるかどうかはわかりません。

私はこのようなものを描いています:

_func createPublisher() -> some Publisher where Output = Int, Failure = Error {
    return Just(1)
}
_
3
jchitel

_some Publisher_(迷惑な制限)で運がありませんでした。

1つのオプションは、AnyPublisherを使用することです。

_func a() -> AnyPublisher<(a: Int, b: String), Never> {
    return Just((a: 1, b: "two")).eraseToAnyPublisher()
}

func b() -> AnyPublisher<String, Never> {
    return a().map(\.b).eraseToAnyPublisher()
}

a().sink(receiveValue: {
    let x = $0 // (a: 1, b: "two)
})

b().sink(receiveValue: {
    let x = $0 // "two"
})
_

あるいは、「Appleの方法」(標準ライブラリで使用する方法)は型エイリアス(またはラッパー構造体)のようです。

_enum PublisherUtils {
    typealias A = Just<(a: Int, b: String)>
    typealias B = Publishers.MapKeyPath<A, String>
    // or implement a simple wrapper struct like what Combine does
}

func a() -> PublisherUtils.A {
    return Just((a: 1, b: "two"))
}

func b() -> PublisherUtils.B {
    return a().map(\.b)
}

a().sink(receiveValue: {
    let x = $0 // (a: 1, b: "two)
})

b().sink(receiveValue: {
    let x = $0 // "two"
})
_

これがCombineフレームワークのPublishers名前空間の目的です。

構造体は型エイリアスよりも不透明です。型エイリアスはCannot convert Utils.MyTypeAlias (aka 'TheLongUnderlyingTypeOf') to expected type ABCのようなエラーメッセージを引き起こす可能性があるため、適切な不透明型に最も近いのは、構造体を使用することです。これは基本的にAnyPublisherです。

0
Potassium Ion

不透明な戻り値では、型はクロージャーから正確に返されるものによって定義されるので、

func createPublisher() -> some Publisher {
    return Just(1)
}

let cancellable = createPublisher()
   .print()
   .sink(receiveCompletion: { _ in
       print(">> done")
   }) { value in
       print(">> \(value)")
   }

// ... all other code here

そしてそれは動作します。 Xcode 11.4でテスト済み。

demo

0
Asperi