|
|
@@ -12,279 +12,265 @@
|
|
|
// See the License for the specific language governing permissions and
|
|
|
// limitations under the License.
|
|
|
|
|
|
-#if canImport(Combine) && swift(>=5.0)
|
|
|
+import Combine
|
|
|
+import FirebaseFirestore
|
|
|
|
|
|
- import Combine
|
|
|
- import FirebaseFirestore
|
|
|
+@available(swift 5.0)
|
|
|
+@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)
|
|
|
+public extension DocumentReference {
|
|
|
+ // MARK: - Set Data
|
|
|
|
|
|
- #if canImport(FirebaseFirestoreSwift)
|
|
|
-
|
|
|
- import FirebaseFirestoreSwift
|
|
|
-
|
|
|
- #endif
|
|
|
+ /// Overwrites the document referred to by this `DocumentReference`. If no document exists, it
|
|
|
+ /// is created. If a document already exists, it is overwritten.
|
|
|
+ ///
|
|
|
+ /// - Parameter documentData: A `Dictionary` containing the fields that make up the document to
|
|
|
+ /// be written.
|
|
|
+ /// - Returns: A publisher emitting a `Void` value once the document has been successfully
|
|
|
+ /// written to the server. This publisher will not emit while the client is offline, though
|
|
|
+ /// local changes will be visible immediately.
|
|
|
+ func setData(_ documentData: [String: Any]) -> Future<Void, Error> {
|
|
|
+ Future { promise in
|
|
|
+ self.setData(documentData) { error in
|
|
|
+ if let error {
|
|
|
+ promise(.failure(error))
|
|
|
+ } else {
|
|
|
+ promise(.success(()))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- @available(swift 5.0)
|
|
|
- @available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)
|
|
|
- public extension DocumentReference {
|
|
|
- // MARK: - Set Data
|
|
|
+ /// Writes to the document referred to by this `DocumentReference`. If the document does not yet
|
|
|
+ /// exist, it will be created. If you pass `merge: true`, the provided data will be merged into
|
|
|
+ /// any existing document.
|
|
|
+ ///
|
|
|
+ /// - Parameters:
|
|
|
+ /// - documentData: A `Dictionary` containing the fields that make up the document to be
|
|
|
+ /// written.
|
|
|
+ /// - merge: Whether to merge the provided data into any existing document.
|
|
|
+ /// - Returns: A publisher emitting a `Void` value once the document has been successfully
|
|
|
+ /// written to the server. This publisher will not emit while the client is offline, though
|
|
|
+ /// local changes will be visible immediately.
|
|
|
+ func setData(_ documentData: [String: Any], merge: Bool) -> Future<Void, Error> {
|
|
|
+ Future { promise in
|
|
|
+ self.setData(documentData, merge: merge) { error in
|
|
|
+ if let error {
|
|
|
+ promise(.failure(error))
|
|
|
+ } else {
|
|
|
+ promise(.success(()))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- /// Overwrites the document referred to by this `DocumentReference`. If no document exists, it
|
|
|
- /// is created. If a document already exists, it is overwritten.
|
|
|
- ///
|
|
|
- /// - Parameter documentData: A `Dictionary` containing the fields that make up the document to
|
|
|
- /// be written.
|
|
|
- /// - Returns: A publisher emitting a `Void` value once the document has been successfully
|
|
|
- /// written to the server. This publisher will not emit while the client is offline, though
|
|
|
- /// local changes will be visible immediately.
|
|
|
- func setData(_ documentData: [String: Any]) -> Future<Void, Error> {
|
|
|
- Future { promise in
|
|
|
- self.setData(documentData) { error in
|
|
|
- if let error {
|
|
|
- promise(.failure(error))
|
|
|
- } else {
|
|
|
- promise(.success(()))
|
|
|
- }
|
|
|
+ /// Writes to the document referred to by this `DocumentReference` and only replace the fields
|
|
|
+ /// specified under `mergeFields`. Any field that is not specified in `mergeFields` is ignored
|
|
|
+ /// and remains untouched. If the document doesn't yet exist, this method creates it and then
|
|
|
+ /// sets the data.
|
|
|
+ ///
|
|
|
+ /// - Parameters:
|
|
|
+ /// - documentData: A `Dictionary` containing the fields that make up the document to be
|
|
|
+ /// written.
|
|
|
+ /// - mergeFields: An `Array` that contains a list of `String` or `FieldPath` elements
|
|
|
+ /// specifying which fields to merge. Fields can contain dots to reference nested fields
|
|
|
+ /// within the document.
|
|
|
+ /// - Returns: A publisher emitting a `Void` value once the document has been successfully
|
|
|
+ /// written to the server. This publisher will not emit while the client is offline, though
|
|
|
+ /// local changes will be visible immediately.
|
|
|
+ func setData(_ documentData: [String: Any], mergeFields: [Any]) -> Future<Void, Error> {
|
|
|
+ Future { promise in
|
|
|
+ self.setData(documentData, mergeFields: mergeFields) { error in
|
|
|
+ if let error {
|
|
|
+ promise(.failure(error))
|
|
|
+ } else {
|
|
|
+ promise(.success(()))
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- /// Writes to the document referred to by this `DocumentReference`. If the document does not yet
|
|
|
- /// exist, it will be created. If you pass `merge: true`, the provided data will be merged into
|
|
|
- /// any existing document.
|
|
|
- ///
|
|
|
- /// - Parameters:
|
|
|
- /// - documentData: A `Dictionary` containing the fields that make up the document to be
|
|
|
- /// written.
|
|
|
- /// - merge: Whether to merge the provided data into any existing document.
|
|
|
- /// - Returns: A publisher emitting a `Void` value once the document has been successfully
|
|
|
- /// written to the server. This publisher will not emit while the client is offline, though
|
|
|
- /// local changes will be visible immediately.
|
|
|
- func setData(_ documentData: [String: Any], merge: Bool) -> Future<Void, Error> {
|
|
|
- Future { promise in
|
|
|
- self.setData(documentData, merge: merge) { error in
|
|
|
+ /// Encodes an instance of `Encodable` and overwrites the encoded data to the document
|
|
|
+ /// referred by this `DocumentReference`. If no document exists, it is created. If a
|
|
|
+ /// document already exists, it is overwritten.
|
|
|
+ ///
|
|
|
+ /// - Parameters:
|
|
|
+ /// - value: An instance of `Encodable` to be encoded to a document.
|
|
|
+ /// - encoder: An encoder instance to use to run the encoding.
|
|
|
+ /// - Returns: A publisher emitting a `Void` value once the document has been successfully
|
|
|
+ /// written to the server. This publisher will not emit while the client is offline, though
|
|
|
+ /// local changes will be visible immediately.
|
|
|
+ func setData<T: Encodable>(from value: T,
|
|
|
+ encoder: Firestore.Encoder = Firestore.Encoder()) -> Future<
|
|
|
+ Void,
|
|
|
+ Error
|
|
|
+ > {
|
|
|
+ Future { promise in
|
|
|
+ do {
|
|
|
+ try self.setData(from: value, encoder: encoder) { error in
|
|
|
if let error {
|
|
|
promise(.failure(error))
|
|
|
} else {
|
|
|
promise(.success(()))
|
|
|
}
|
|
|
}
|
|
|
+ } catch {
|
|
|
+ promise(.failure(error))
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- /// Writes to the document referred to by this `DocumentReference` and only replace the fields
|
|
|
- /// specified under `mergeFields`. Any field that is not specified in `mergeFields` is ignored
|
|
|
- /// and remains untouched. If the document doesn't yet exist, this method creates it and then
|
|
|
- /// sets the data.
|
|
|
- ///
|
|
|
- /// - Parameters:
|
|
|
- /// - documentData: A `Dictionary` containing the fields that make up the document to be
|
|
|
- /// written.
|
|
|
- /// - mergeFields: An `Array` that contains a list of `String` or `FieldPath` elements
|
|
|
- /// specifying which fields to merge. Fields can contain dots to reference nested fields
|
|
|
- /// within the document.
|
|
|
- /// - Returns: A publisher emitting a `Void` value once the document has been successfully
|
|
|
- /// written to the server. This publisher will not emit while the client is offline, though
|
|
|
- /// local changes will be visible immediately.
|
|
|
- func setData(_ documentData: [String: Any], mergeFields: [Any]) -> Future<Void, Error> {
|
|
|
- Future { promise in
|
|
|
- self.setData(documentData, mergeFields: mergeFields) { error in
|
|
|
+ /// Encodes an instance of `Encodable` and overwrites the encoded data to the document
|
|
|
+ /// referred
|
|
|
+ /// by this `DocumentReference`. If no document exists, it is created. If a document already
|
|
|
+ /// exists, it is overwritten. If you pass `merge: true`, the provided Encodable will be
|
|
|
+ /// merged
|
|
|
+ /// into any existing document.
|
|
|
+ ///
|
|
|
+ /// - Parameters:
|
|
|
+ /// - value: An instance of `Encodable` to be encoded to a document.
|
|
|
+ /// - merge: Whether to merge the provided data into any existing document.
|
|
|
+ /// - encoder: An encoder instance to use to run the encoding.
|
|
|
+ /// - Returns: A publisher emitting a `Void` value once the document has been successfully
|
|
|
+ /// written to the server. This publisher will not emit while the client is offline, though
|
|
|
+ /// local changes will be visible immediately.
|
|
|
+ func setData<T: Encodable>(from value: T, merge: Bool,
|
|
|
+ encoder: Firestore.Encoder = Firestore.Encoder()) -> Future<
|
|
|
+ Void,
|
|
|
+ Error
|
|
|
+ > {
|
|
|
+ Future { promise in
|
|
|
+ do {
|
|
|
+ try self.setData(from: value, merge: merge, encoder: encoder) { error in
|
|
|
if let error {
|
|
|
promise(.failure(error))
|
|
|
} else {
|
|
|
promise(.success(()))
|
|
|
}
|
|
|
}
|
|
|
+ } catch {
|
|
|
+ promise(.failure(error))
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- #if canImport(FirebaseFirestoreSwift)
|
|
|
-
|
|
|
- /// Encodes an instance of `Encodable` and overwrites the encoded data to the document
|
|
|
- /// referred by this `DocumentReference`. If no document exists, it is created. If a
|
|
|
- /// document already exists, it is overwritten.
|
|
|
- ///
|
|
|
- /// - Parameters:
|
|
|
- /// - value: An instance of `Encodable` to be encoded to a document.
|
|
|
- /// - encoder: An encoder instance to use to run the encoding.
|
|
|
- /// - Returns: A publisher emitting a `Void` value once the document has been successfully
|
|
|
- /// written to the server. This publisher will not emit while the client is offline, though
|
|
|
- /// local changes will be visible immediately.
|
|
|
- func setData<T: Encodable>(from value: T,
|
|
|
- encoder: Firestore.Encoder = Firestore.Encoder()) -> Future<
|
|
|
- Void,
|
|
|
- Error
|
|
|
- > {
|
|
|
- Future { promise in
|
|
|
- do {
|
|
|
- try self.setData(from: value, encoder: encoder) { error in
|
|
|
- if let error {
|
|
|
- promise(.failure(error))
|
|
|
- } else {
|
|
|
- promise(.success(()))
|
|
|
- }
|
|
|
- }
|
|
|
- } catch {
|
|
|
- promise(.failure(error))
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// Encodes an instance of `Encodable` and overwrites the encoded data to the document
|
|
|
- /// referred
|
|
|
- /// by this `DocumentReference`. If no document exists, it is created. If a document already
|
|
|
- /// exists, it is overwritten. If you pass `merge: true`, the provided Encodable will be
|
|
|
- /// merged
|
|
|
- /// into any existing document.
|
|
|
- ///
|
|
|
- /// - Parameters:
|
|
|
- /// - value: An instance of `Encodable` to be encoded to a document.
|
|
|
- /// - merge: Whether to merge the provided data into any existing document.
|
|
|
- /// - encoder: An encoder instance to use to run the encoding.
|
|
|
- /// - Returns: A publisher emitting a `Void` value once the document has been successfully
|
|
|
- /// written to the server. This publisher will not emit while the client is offline, though
|
|
|
- /// local changes will be visible immediately.
|
|
|
- func setData<T: Encodable>(from value: T, merge: Bool,
|
|
|
- encoder: Firestore.Encoder = Firestore.Encoder()) -> Future<
|
|
|
- Void,
|
|
|
- Error
|
|
|
- > {
|
|
|
- Future { promise in
|
|
|
- do {
|
|
|
- try self.setData(from: value, merge: merge, encoder: encoder) { error in
|
|
|
- if let error {
|
|
|
- promise(.failure(error))
|
|
|
- } else {
|
|
|
- promise(.success(()))
|
|
|
- }
|
|
|
- }
|
|
|
- } catch {
|
|
|
- promise(.failure(error))
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// Encodes an instance of `Encodable` and writes the encoded data to the document referred by
|
|
|
- /// this `DocumentReference` by only replacing the fields specified under mergeFields. Any
|
|
|
- /// field
|
|
|
- /// that is not specified in mergeFields is ignored and remains untouched. If the document
|
|
|
- /// doesn’t yet exist, this method creates it and then sets the data.
|
|
|
- ///
|
|
|
- /// - Parameters:
|
|
|
- /// - value: An instance of `Encodable` to be encoded to a document.
|
|
|
- /// - mergeFields: An `Array` that contains a list of `String` or `FieldPath` elements
|
|
|
- /// specifying which fields to merge. Fields can contain dots to reference nested fields
|
|
|
- /// within the document.
|
|
|
- /// - encoder: An encoder instance to use to run the encoding.
|
|
|
- /// - Returns: A publisher emitting a `Void` value once the document has been successfully
|
|
|
- /// written to the server. This publisher will not emit while the client is offline, though
|
|
|
- /// local changes will be visible immediately.
|
|
|
- func setData<T: Encodable>(from value: T, mergeFields: [Any],
|
|
|
- encoder: Firestore.Encoder = Firestore.Encoder()) -> Future<
|
|
|
- Void,
|
|
|
- Error
|
|
|
- > {
|
|
|
- Future { promise in
|
|
|
- do {
|
|
|
- try self.setData(from: value, mergeFields: mergeFields, encoder: encoder) { error in
|
|
|
- if let error {
|
|
|
- promise(.failure(error))
|
|
|
- } else {
|
|
|
- promise(.success(()))
|
|
|
- }
|
|
|
- }
|
|
|
- } catch {
|
|
|
- promise(.failure(error))
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- #endif
|
|
|
-
|
|
|
- // MARK: - Update Data
|
|
|
-
|
|
|
- /// Updates fields in the document referred to by this `DocumentReference`. If the document does
|
|
|
- /// not exist, the update fails and the specified completion block receives an error.
|
|
|
- ///
|
|
|
- /// - Parameter documentData: A `Dictionary` containing the fields (expressed as a `String` or
|
|
|
- /// `FieldPath`) and values with which to update the document.
|
|
|
- /// - Returns: A publisher emitting a `Void` when the update is complete. This block will only
|
|
|
- /// execute when the client is online and the commit has completed against the server. This
|
|
|
- /// publisher will not emit while the device is offline, though local changes will be visible
|
|
|
- /// immediately.
|
|
|
- func updateData(_ documentData: [String: Any]) -> Future<Void, Error> {
|
|
|
- Future { promise in
|
|
|
- self.updateData(documentData) { error in
|
|
|
+ /// Encodes an instance of `Encodable` and writes the encoded data to the document referred by
|
|
|
+ /// this `DocumentReference` by only replacing the fields specified under mergeFields. Any
|
|
|
+ /// field
|
|
|
+ /// that is not specified in mergeFields is ignored and remains untouched. If the document
|
|
|
+ /// doesn’t yet exist, this method creates it and then sets the data.
|
|
|
+ ///
|
|
|
+ /// - Parameters:
|
|
|
+ /// - value: An instance of `Encodable` to be encoded to a document.
|
|
|
+ /// - mergeFields: An `Array` that contains a list of `String` or `FieldPath` elements
|
|
|
+ /// specifying which fields to merge. Fields can contain dots to reference nested fields
|
|
|
+ /// within the document.
|
|
|
+ /// - encoder: An encoder instance to use to run the encoding.
|
|
|
+ /// - Returns: A publisher emitting a `Void` value once the document has been successfully
|
|
|
+ /// written to the server. This publisher will not emit while the client is offline, though
|
|
|
+ /// local changes will be visible immediately.
|
|
|
+ func setData<T: Encodable>(from value: T, mergeFields: [Any],
|
|
|
+ encoder: Firestore.Encoder = Firestore.Encoder()) -> Future<
|
|
|
+ Void,
|
|
|
+ Error
|
|
|
+ > {
|
|
|
+ Future { promise in
|
|
|
+ do {
|
|
|
+ try self.setData(from: value, mergeFields: mergeFields, encoder: encoder) { error in
|
|
|
if let error {
|
|
|
promise(.failure(error))
|
|
|
} else {
|
|
|
promise(.success(()))
|
|
|
}
|
|
|
}
|
|
|
+ } catch {
|
|
|
+ promise(.failure(error))
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- // MARK: - Delete
|
|
|
+ // MARK: - Update Data
|
|
|
|
|
|
- /// Deletes the document referred to by this `DocumentReference`.
|
|
|
- ///
|
|
|
- /// - Returns: A publisher emitting a `Void` when the document has been deleted from the server.
|
|
|
- /// This publisher will not emit while the device is offline, though local changes will be
|
|
|
- /// visible immediately.
|
|
|
- func delete() -> Future<Void, Error> {
|
|
|
- Future { promise in
|
|
|
- self.delete { error in
|
|
|
- if let error {
|
|
|
- promise(.failure(error))
|
|
|
- } else {
|
|
|
- promise(.success(()))
|
|
|
- }
|
|
|
+ /// Updates fields in the document referred to by this `DocumentReference`. If the document does
|
|
|
+ /// not exist, the update fails and the specified completion block receives an error.
|
|
|
+ ///
|
|
|
+ /// - Parameter documentData: A `Dictionary` containing the fields (expressed as a `String` or
|
|
|
+ /// `FieldPath`) and values with which to update the document.
|
|
|
+ /// - Returns: A publisher emitting a `Void` when the update is complete. This block will only
|
|
|
+ /// execute when the client is online and the commit has completed against the server. This
|
|
|
+ /// publisher will not emit while the device is offline, though local changes will be visible
|
|
|
+ /// immediately.
|
|
|
+ func updateData(_ documentData: [String: Any]) -> Future<Void, Error> {
|
|
|
+ Future { promise in
|
|
|
+ self.updateData(documentData) { error in
|
|
|
+ if let error {
|
|
|
+ promise(.failure(error))
|
|
|
+ } else {
|
|
|
+ promise(.success(()))
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- // MARK: - Get Document
|
|
|
+ // MARK: - Delete
|
|
|
|
|
|
- /// Reads the document referenced by this `DocumentReference`.
|
|
|
- ///
|
|
|
- /// - Parameter source: Indicates whether the results should be fetched from the cache only
|
|
|
- /// (`Source.cache`), the server only (`Source.server`), or to attempt the server and fall back
|
|
|
- /// to the cache (`Source.default`).
|
|
|
- /// - Returns: A publisher emitting a `DocumentSnapshot` instance.
|
|
|
- func getDocument(source: FirestoreSource = .default)
|
|
|
- -> Future<DocumentSnapshot, Error> {
|
|
|
- Future { promise in
|
|
|
- self.getDocument(source: source) { snapshot, error in
|
|
|
- if let error {
|
|
|
- promise(.failure(error))
|
|
|
- } else if let snapshot {
|
|
|
- promise(.success(snapshot))
|
|
|
- }
|
|
|
+ /// Deletes the document referred to by this `DocumentReference`.
|
|
|
+ ///
|
|
|
+ /// - Returns: A publisher emitting a `Void` when the document has been deleted from the server.
|
|
|
+ /// This publisher will not emit while the device is offline, though local changes will be
|
|
|
+ /// visible immediately.
|
|
|
+ func delete() -> Future<Void, Error> {
|
|
|
+ Future { promise in
|
|
|
+ self.delete { error in
|
|
|
+ if let error {
|
|
|
+ promise(.failure(error))
|
|
|
+ } else {
|
|
|
+ promise(.success(()))
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- // MARK: - Snapshot Publisher
|
|
|
+ // MARK: - Get Document
|
|
|
|
|
|
- /// Registers a publisher that publishes document snapshot changes.
|
|
|
- ///
|
|
|
- /// - Parameter includeMetadataChanges: Whether metadata-only changes (i.e. only
|
|
|
- /// `DocumentSnapshot.metadata` changed) should trigger snapshot events.
|
|
|
- /// - Returns: A publisher emitting `DocumentSnapshot` instances.
|
|
|
- func snapshotPublisher(includeMetadataChanges: Bool = false)
|
|
|
- -> AnyPublisher<DocumentSnapshot, Error> {
|
|
|
- let subject = PassthroughSubject<DocumentSnapshot, Error>()
|
|
|
- let listenerHandle =
|
|
|
- addSnapshotListener(includeMetadataChanges: includeMetadataChanges) { snapshot, error in
|
|
|
- if let error {
|
|
|
- subject.send(completion: .failure(error))
|
|
|
- } else if let snapshot {
|
|
|
- subject.send(snapshot)
|
|
|
- }
|
|
|
+ /// Reads the document referenced by this `DocumentReference`.
|
|
|
+ ///
|
|
|
+ /// - Parameter source: Indicates whether the results should be fetched from the cache only
|
|
|
+ /// (`Source.cache`), the server only (`Source.server`), or to attempt the server and fall back
|
|
|
+ /// to the cache (`Source.default`).
|
|
|
+ /// - Returns: A publisher emitting a `DocumentSnapshot` instance.
|
|
|
+ func getDocument(source: FirestoreSource = .default)
|
|
|
+ -> Future<DocumentSnapshot, Error> {
|
|
|
+ Future { promise in
|
|
|
+ self.getDocument(source: source) { snapshot, error in
|
|
|
+ if let error {
|
|
|
+ promise(.failure(error))
|
|
|
+ } else if let snapshot {
|
|
|
+ promise(.success(snapshot))
|
|
|
}
|
|
|
- return subject
|
|
|
- .handleEvents(receiveCancel: listenerHandle.remove)
|
|
|
- .eraseToAnyPublisher()
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-#endif
|
|
|
+ // MARK: - Snapshot Publisher
|
|
|
+
|
|
|
+ /// Registers a publisher that publishes document snapshot changes.
|
|
|
+ ///
|
|
|
+ /// - Parameter includeMetadataChanges: Whether metadata-only changes (i.e. only
|
|
|
+ /// `DocumentSnapshot.metadata` changed) should trigger snapshot events.
|
|
|
+ /// - Returns: A publisher emitting `DocumentSnapshot` instances.
|
|
|
+ func snapshotPublisher(includeMetadataChanges: Bool = false)
|
|
|
+ -> AnyPublisher<DocumentSnapshot, Error> {
|
|
|
+ let subject = PassthroughSubject<DocumentSnapshot, Error>()
|
|
|
+ let listenerHandle =
|
|
|
+ addSnapshotListener(includeMetadataChanges: includeMetadataChanges) { snapshot, error in
|
|
|
+ if let error {
|
|
|
+ subject.send(completion: .failure(error))
|
|
|
+ } else if let snapshot {
|
|
|
+ subject.send(snapshot)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return subject
|
|
|
+ .handleEvents(receiveCancel: listenerHandle.remove)
|
|
|
+ .eraseToAnyPublisher()
|
|
|
+ }
|
|
|
+}
|