diff --git a/AltStore/Managing Apps/AppManager.swift b/AltStore/Managing Apps/AppManager.swift index 0f90ae70..191857d8 100644 --- a/AltStore/Managing Apps/AppManager.swift +++ b/AltStore/Managing Apps/AppManager.swift @@ -67,6 +67,15 @@ final class AppManager } } + private lazy var progressLock: UnsafeMutablePointer = { + // Can't safely pass &os_unfair_lock to os_unfair_lock functions in Swift, + // so pass UnsafeMutablePointer instead which is guaranteed to be safe. + // https://stackoverflow.com/a/68615042 + let lock = UnsafeMutablePointer.allocate(capacity: 1) + lock.initialize(to: .init()) + return lock + }() + @available(iOS 13, *) private(set) var publisher: AppManagerPublisher { get { _publisher as! AppManagerPublisher } @@ -102,6 +111,13 @@ final class AppManager } } + deinit + { + // Should never be called, but do bookkeeping anyway. + self.progressLock.deinitialize(count: 1) + self.progressLock.deallocate() + } + @available(iOS 13, *) func prepareSubscriptions() { @@ -801,12 +817,18 @@ extension AppManager func installationProgress(for app: AppProtocol) -> Progress? { + os_unfair_lock_lock(self.progressLock) + defer { os_unfair_lock_unlock(self.progressLock) } + let progress = self.installationProgress[app.bundleIdentifier] return progress } func refreshProgress(for app: AppProtocol) -> Progress? { + os_unfair_lock_lock(self.progressLock) + defer { os_unfair_lock_unlock(self.progressLock) } + let progress = self.refreshProgress[app.bundleIdentifier] return progress } @@ -2092,6 +2114,9 @@ private extension AppManager func progress(for operation: AppOperation) -> Progress? { + os_unfair_lock_lock(self.progressLock) + defer { os_unfair_lock_unlock(self.progressLock) } + switch operation { case .install, .update: return self.installationProgress[operation.bundleIdentifier] @@ -2101,6 +2126,9 @@ private extension AppManager func set(_ progress: Progress?, for operation: AppOperation) { + os_unfair_lock_lock(self.progressLock) + defer { os_unfair_lock_unlock(self.progressLock) } + switch operation { case .install, .update: self.installationProgress[operation.bundleIdentifier] = progress