Objective-CコードをSwiftに移植するとき、新しいCombine
フレームワークと、それを使用して一般的なデザインパターンを再作成する方法をよりよく理解しようとしています。
この場合、デザインパターンは単一のオブジェクト(Manager、Serviceなど)であり、コールバックを受信するためのデリゲートとして任意の数の「クライアント」に登録できます。これは、デリゲートを使用する基本的な1:多パターンです。
Combine
はこれに理想的ですが、サンプルコードは少し薄いです。以下は実際の例ですが、それが正しいか、意図したとおりに使用されているかはわかりません。特に、オブジェクト間の参照サイクルに興味があります。
class Service {
let tweets = PassthroughSubject<String, Never>()
func start() {
// Simulate the need send to send updates.
DispatchQueue.global(qos: .utility).async {
while true {
self.sendTweet()
usleep(100000)
}
}
}
func sendTweet() {
tweets.send("Message \(Date().timeIntervalSince1970)")
}
}
class Client : Subscriber {
typealias Input = String
typealias Failure = Never
let service:Service
var subscription:Subscription?
init(service:Service) {
self.service = service
// Is this a retain cycle?
// Is this thread-safe?
self.service.tweets.subscribe(self)
}
func receive(subscription: Subscription) {
print("Received subscription: \(subscription)")
self.subscription = subscription
self.subscription?.request(.unlimited)
}
func receive(_ input: String) -> Subscribers.Demand {
print("Received Tweet: \(input)")
return .unlimited
}
func receive(completion: Subscribers.Completion<Never>) {
print("Received completion")
}
}
// Dependency injection is used a lot throughout the
// application in a similar fashion to this:
let service = Service()
let client = Client(service:service)
// In the real world, the service is started when
// the application is launched and clients come-and-go.
service.start()
出力は次のとおりです。
Received subscription: PassthroughSubject
Received Tweet: Message 1560371698.300811
Received Tweet: Message 1560371698.4087949
Received Tweet: Message 1560371698.578027
...
これは、Combine
が意図されていた使用方法にかなり近いですか?
カスタム結合サブスクライバーは、パブリッシャーから受信したサブスクリプションオブジェクトにキャンセルを転送するメソッドを提供するキャンセル可能なプロトコルにも準拠する必要があります。これにより、サブスクリプションプロパティを公開する必要がなくなります。ドキュメントによると:
カスタムサブスクライバーを作成する場合、パブリッシャーは最初にサブスクライブするときにSubscriptionオブジェクトを送信します。このサブスクリプションを保存し、発行をキャンセルする場合は、cancel()メソッドを呼び出します。カスタムサブスクライバーを作成するときは、Cancellableプロトコルを実装し、cancel()実装で呼び出しを保存されたサブスクリプションに転送する必要があります。 https://developer.Apple.com/documentation/combine/ception_and_handling_events_with_combine