diff --git a/Sources/Defaults/Observation+Combine.swift b/Sources/Defaults/Observation+Combine.swift index 16f4e11..c045f3e 100644 --- a/Sources/Defaults/Observation+Combine.swift +++ b/Sources/Defaults/Observation+Combine.swift @@ -102,7 +102,7 @@ extension Defaults { - Warning: This method exists for backwards compatibility and will be deprecated sometime in the future. Use ``Defaults/updates(_:initial:)-9eh8`` instead. */ public static func publisher( - keys: _AnyKey..., + keys: [_AnyKey], options: ObservationOptions = [.initial] ) -> AnyPublisher { let initial = Empty(completeImmediately: false).eraseToAnyPublisher() @@ -118,4 +118,16 @@ extension Defaults { combined.merge(with: keyPublisher).eraseToAnyPublisher() } } + + /** + Publisher for multiple `Key` observation, but without specific information about changes. + + - Warning: This method exists for backwards compatibility and will be deprecated sometime in the future. Use ``Defaults/updates(_:initial:)-9eh8`` instead. + */ + public static func publisher( + keys: _AnyKey..., + options: ObservationOptions = [.initial] + ) -> AnyPublisher { + publisher(keys: keys, options: options) + } } diff --git a/Sources/Defaults/Observation.swift b/Sources/Defaults/Observation.swift index 858a75c..06d2d74 100644 --- a/Sources/Defaults/Observation.swift +++ b/Sources/Defaults/Observation.swift @@ -125,6 +125,7 @@ extension Defaults { private weak var object: UserDefaults? private let key: String private let callback: Callback + private var isObserving = false init(object: UserDefaults, key: String, callback: @escaping Callback) { self.object = object @@ -138,10 +139,15 @@ extension Defaults { func start(options: ObservationOptions) { object?.addObserver(self, forKeyPath: key, options: options.toNSKeyValueObservingOptions, context: nil) + isObserving = true } func invalidate() { - object?.removeObserver(self, forKeyPath: key, context: nil) + if isObserving { + object?.removeObserver(self, forKeyPath: key, context: nil) + isObserving = false + } + object = nil lifetimeAssociation?.cancel() } diff --git a/Tests/DefaultsTests/DefaultsTests.swift b/Tests/DefaultsTests/DefaultsTests.swift index 2108c1c..8ef82e3 100644 --- a/Tests/DefaultsTests/DefaultsTests.swift +++ b/Tests/DefaultsTests/DefaultsTests.swift @@ -733,6 +733,23 @@ final class DefaultsTests: XCTestCase { waitForExpectations(timeout: 10) } + func testImmediatelyFinishingMultiplePublisherCombine() { + let key1 = Defaults.Key("observeKey1", default: false) + let key2 = Defaults.Key("observeKey2", default: "🦄") + let expect = expectation(description: "Observation closure being called without crashing") + + let cancellable = Defaults + .publisher(keys: [key1, key2], options: [.initial]) + .first() + .sink { _ in + expect.fulfill() + } + + cancellable.cancel() + + waitForExpectations(timeout: 10) + } + func testKeyEquatable() { XCTAssertEqual(Defaults.Key("equatableKeyTest", default: false), Defaults.Key("equatableKeyTest", default: false)) }