Skip to content

Commit 175dc7d

Browse files
author
Brennan Stehling
committed
makes StorageBackgroundEventsRegistry work as a singleton so the actor protects state
1 parent fbde41b commit 175dc7d

File tree

5 files changed

+43
-27
lines changed

5 files changed

+43
-27
lines changed

AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/AWSS3StoragePlugin+AsyncClientBehavior.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ extension AWSS3StoragePlugin {
120120
}
121121

122122
public func handleEventsForBackgroundURLSession(identifier: String) async -> Bool {
123-
await StorageBackgroundEventsRegistry.handleEventsForBackgroundURLSession(identifier: identifier)
123+
await StorageBackgroundEventsRegistry.shared.handleEventsForBackgroundURLSession(identifier: identifier)
124124
}
125125

126126
}

AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift

+6-2
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,9 @@ class AWSS3StorageService: AWSS3StorageServiceBehaviour, StorageServiceProxy {
108108
self.awsS3 = awsS3
109109
self.bucket = bucket
110110

111-
StorageBackgroundEventsRegistry.register(identifier: identifier)
111+
Task {
112+
await StorageBackgroundEventsRegistry.shared.register(identifier: identifier)
113+
}
112114

113115
delegate.storageService = self
114116

@@ -125,7 +127,9 @@ class AWSS3StorageService: AWSS3StorageServiceBehaviour, StorageServiceProxy {
125127
}
126128

127129
deinit {
128-
StorageBackgroundEventsRegistry.unregister(identifier: identifier)
130+
Task {
131+
await StorageBackgroundEventsRegistry.shared.unregister(identifier: identifier)
132+
}
129133
}
130134

131135
func reset() {

AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageBackgroundEventsRegistry.swift

+17-9
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,26 @@ extension Notification.Name {
1818
/// independently of the Amplify Storage plugin and this function will indiciate if it will handle the given identifier.
1919
actor StorageBackgroundEventsRegistry {
2020
typealias StorageBackgroundEventsContinuation = CheckedContinuation<Bool, Never>
21-
static var identifier: String?
22-
static var continuation: StorageBackgroundEventsContinuation?
21+
22+
@MainActor
23+
static let shared = StorageBackgroundEventsRegistry()
24+
25+
private var identifier: String?
26+
private var continuation: StorageBackgroundEventsContinuation?
2327

2428
// override for use with unit tests
25-
static var notificationCenter: NotificationCenter?
29+
internal private(set) var notificationCenter: NotificationCenter?
30+
31+
func change(notificationCenter: NotificationCenter?) {
32+
self.notificationCenter = notificationCenter
33+
}
2634

2735
/// Handles background events for URLSession on iOS.
2836
/// - Parameters:
2937
/// - identifier: session identifier
3038
/// - completionHandler: completion handler
3139
/// - Returns: indicates if the identifier was registered and will be handled
32-
static func handleEventsForBackgroundURLSession(identifier: String) async -> Bool {
40+
func handleEventsForBackgroundURLSession(identifier: String) async -> Bool {
3341
guard self.identifier == identifier else { return false }
3442

3543
return await withCheckedContinuation { (continuation: CheckedContinuation<Bool, Never>) in
@@ -41,29 +49,29 @@ actor StorageBackgroundEventsRegistry {
4149
/// Notifies observes when waiting for continuation to be resumed.
4250
/// - Parameters:
4351
/// - identifier: session identifier
44-
private static func notifyWaiting(for identifier: String) {
52+
private func notifyWaiting(for identifier: String) {
4553
notificationCenter?.post(name: Notification.Name.StorageBackgroundEventsRegistryWaiting, object: identifier)
4654
}
4755

4856
// The storage plugin will register the session identifier when it is configured.
49-
static func register(identifier: String) {
57+
func register(identifier: String) {
5058
self.identifier = identifier
5159
}
5260

5361
// When the storage function is deinitialized it will unregister the session identifier.
54-
static func unregister(identifier: String) {
62+
func unregister(identifier: String) {
5563
if self.identifier == identifier {
5664
self.identifier = nil
5765
}
5866
}
5967

6068
// When URLSession is done processing background events it will use this function to get the completion handler.
61-
static func getContinuation(for identifier: String) -> StorageBackgroundEventsContinuation? {
69+
func getContinuation(for identifier: String) -> StorageBackgroundEventsContinuation? {
6270
self.identifier == identifier ? continuation : nil
6371
}
6472

6573
// Once the background event completion handler is used it can be cleared.
66-
static func removeContinuation(for identifier: String) {
74+
func removeContinuation(for identifier: String) {
6775
if self.identifier == identifier {
6876
self.continuation = nil
6977
}

AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageServiceSessionDelegate.swift

+8-6
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,15 @@ extension StorageServiceSessionDelegate: URLSessionDelegate {
5353
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
5454
logURLSessionActivity("Session did finish background events")
5555

56-
if let identifier = session.configuration.identifier,
57-
let continuation = StorageBackgroundEventsRegistry.getContinuation(for: identifier) {
58-
// Must be run on main thread as covered by Apple Developer docs.
59-
Task { @MainActor in
60-
continuation.resume(returning: true)
56+
Task {
57+
if let identifier = session.configuration.identifier,
58+
let continuation = await StorageBackgroundEventsRegistry.shared.getContinuation(for: identifier) {
59+
// Must be run on main thread as covered by Apple Developer docs.
60+
Task { @MainActor in
61+
continuation.resume(returning: true)
62+
}
63+
await StorageBackgroundEventsRegistry.shared.removeContinuation(for: identifier)
6164
}
62-
StorageBackgroundEventsRegistry.removeContinuation(for: identifier)
6365
}
6466
}
6567

AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Support/Internal/StorageBackgroundEventsRegistryTests.swift

+11-9
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ class StorageBackgroundEventsRegistryTests: XCTestCase {
1616
func testRegisteringAndUnregister() async throws {
1717
let identifier = UUID().uuidString
1818
let otherIdentifier = UUID().uuidString
19-
StorageBackgroundEventsRegistry.register(identifier: identifier)
19+
await StorageBackgroundEventsRegistry.shared.register(identifier: identifier)
2020

2121
let notificationCenter = NotificationCenter()
22-
StorageBackgroundEventsRegistry.notificationCenter = notificationCenter
22+
await StorageBackgroundEventsRegistry.shared.change(notificationCenter: notificationCenter)
2323
defer {
24-
StorageBackgroundEventsRegistry.notificationCenter = nil
24+
Task {
25+
await StorageBackgroundEventsRegistry.shared.change(notificationCenter: nil)
26+
}
2527
}
2628

2729
let done = asyncExpectation(description: "done")
@@ -39,7 +41,7 @@ class StorageBackgroundEventsRegistryTests: XCTestCase {
3941
}
4042

4143
Task {
42-
let handled = await StorageBackgroundEventsRegistry.handleEventsForBackgroundURLSession(identifier: identifier)
44+
let handled = await StorageBackgroundEventsRegistry.shared.handleEventsForBackgroundURLSession(identifier: identifier)
4345
await done.fulfill()
4446
XCTAssertTrue(handled)
4547
}
@@ -53,7 +55,7 @@ class StorageBackgroundEventsRegistryTests: XCTestCase {
5355
let otherDone = asyncExpectation(description: "other done")
5456

5557
Task {
56-
let otherHandled = await StorageBackgroundEventsRegistry.handleEventsForBackgroundURLSession(identifier: otherIdentifier)
58+
let otherHandled = await StorageBackgroundEventsRegistry.shared.handleEventsForBackgroundURLSession(identifier: otherIdentifier)
5759
await otherDone.fulfill()
5860
XCTAssertFalse(otherHandled)
5961
}
@@ -66,12 +68,12 @@ class StorageBackgroundEventsRegistryTests: XCTestCase {
6668
func testHandlingUnregisteredIdentifier() async throws {
6769
let identifier = UUID().uuidString
6870
let otherIdentifier = UUID().uuidString
69-
StorageBackgroundEventsRegistry.register(identifier: otherIdentifier)
71+
await StorageBackgroundEventsRegistry.shared.register(identifier: otherIdentifier)
7072

7173
let done = asyncExpectation(description: "done")
7274

7375
Task {
74-
let handled = await StorageBackgroundEventsRegistry.handleEventsForBackgroundURLSession(identifier: identifier)
76+
let handled = await StorageBackgroundEventsRegistry.shared.handleEventsForBackgroundURLSession(identifier: identifier)
7577
await done.fulfill()
7678
XCTAssertFalse(handled)
7779
}
@@ -83,9 +85,9 @@ class StorageBackgroundEventsRegistryTests: XCTestCase {
8385
func handleEvents(for identifier: String) async -> Bool {
8486
await Task.yield()
8587

86-
if let continuation = StorageBackgroundEventsRegistry.getContinuation(for: identifier) {
88+
if let continuation = await StorageBackgroundEventsRegistry.shared.getContinuation(for: identifier) {
8789
continuation.resume(returning: true)
88-
StorageBackgroundEventsRegistry.removeContinuation(for: identifier)
90+
await StorageBackgroundEventsRegistry.shared.removeContinuation(for: identifier)
8991
return true
9092
} else {
9193
print("No continuation for identifier: \(identifier)")

0 commit comments

Comments
 (0)