Skip to content

Commit 69247ba

Browse files
authored
Fix crash when cancelling subscription for custom PersistenceKey (#3494)
* Add crashing unit test for AppStorageKey subscription cancellation * Fix double cancellation of Shared.Subscription
1 parent 333aa22 commit 69247ba

File tree

2 files changed

+19
-2
lines changed

2 files changed

+19
-2
lines changed

Sources/ComposableArchitecture/SharedState/PersistenceKey.swift

+3-2
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ extension Shared {
7373
/// This object is returned from ``PersistenceReaderKey/subscribe(initialValue:didSet:)``, which
7474
/// will feed updates from an external system for its lifetime, or till ``cancel()`` is called.
7575
public class Subscription {
76-
let onCancel: () -> Void
76+
var onCancel: (() -> Void)?
7777

7878
/// Initializes the subscription with the given cancel closure.
7979
///
@@ -88,7 +88,8 @@ extension Shared {
8888

8989
/// Cancels the subscription.
9090
public func cancel() {
91-
self.onCancel()
91+
self.onCancel?()
92+
self.onCancel = nil
9293
}
9394
}
9495
}

Tests/ComposableArchitectureTests/SharedTests.swift

+16
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,22 @@ final class SharedTests: XCTestCase {
10841084
}
10851085
}
10861086
}
1087+
1088+
func testPersistenceKeySubscription() async throws {
1089+
let persistenceKey: AppStorageKey<Int> = .appStorage("shared")
1090+
let changes = LockIsolated<[Int?]>([])
1091+
var subscription: Optional = persistenceKey.subscribe(initialValue: nil) { value in
1092+
changes.withValue { $0.append(value) }
1093+
}
1094+
@Dependency(\.defaultAppStorage) var userDefaults
1095+
userDefaults.set(1, forKey: "shared")
1096+
userDefaults.set(42, forKey: "shared")
1097+
subscription?.cancel()
1098+
userDefaults.set(123, forKey: "shared")
1099+
subscription = nil
1100+
XCTAssertEqual([1, 42], changes.value)
1101+
XCTAssertEqual(123, persistenceKey.load(initialValue: nil))
1102+
}
10871103
}
10881104

10891105
@globalActor actor GA: GlobalActor {

0 commit comments

Comments
 (0)