Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions RevenueCat.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
16E146B22E99FC7E0089B609 /* PurchaseResultComparator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16E146B12E99FC7E0089B609 /* PurchaseResultComparator.swift */; };
16E146B52E99FF640089B609 /* MockStoreTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16E146B42E99FF640089B609 /* MockStoreTransaction.swift */; };
16E2B7F12EA01DFA00F04A7A /* SynchronizedLargeItemCacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16E2B7F02EA01DFA00F04A7A /* SynchronizedLargeItemCacheTests.swift */; };
16EE87CE2EE75B49002AC6FE /* SynchronizedUserDefaultsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1639F7BF2EE7594B00652C13 /* SynchronizedUserDefaultsTests.swift */; };
16F376262E93F1E300ADF649 /* LargeItemCacheTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16F376252E93F1E300ADF649 /* LargeItemCacheTypeTests.swift */; };
1D20E1D62EBCF80E00ABE4CD /* HTTPRequestTimeoutManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D20E1D52EBCF80E00ABE4CD /* HTTPRequestTimeoutManager.swift */; };
1D20E1D82EBCF82900ABE4CD /* HTTPRequestTimeoutManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D20E1D72EBCF82900ABE4CD /* HTTPRequestTimeoutManager.swift */; };
Expand Down Expand Up @@ -1553,6 +1554,7 @@
1622D3FA2E900DE000C20E3C /* ChecksumTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChecksumTests.swift; sourceTree = "<group>"; };
1622D3FC2E900F8200C20E3C /* Checksum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checksum.swift; sourceTree = "<group>"; };
1622D40D2E90189F00C20E3C /* URLWithValidation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLWithValidation.swift; sourceTree = "<group>"; };
1639F7BF2EE7594B00652C13 /* SynchronizedUserDefaultsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SynchronizedUserDefaultsTests.swift; sourceTree = "<group>"; };
164681C82E6B577600854AA5 /* VideoComponentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoComponentView.swift; sourceTree = "<group>"; };
164681C92E6B577600854AA5 /* VideoComponentViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoComponentViewModel.swift; sourceTree = "<group>"; };
164681CA2E6B577600854AA5 /* VideoPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4541,6 +4543,7 @@
37E35AE0CDC4C2AA8260FB58 /* Caching */ = {
isa = PBXGroup;
children = (
1639F7BF2EE7594B00652C13 /* SynchronizedUserDefaultsTests.swift */,
16E2B7F02EA01DFA00F04A7A /* SynchronizedLargeItemCacheTests.swift */,
16F376252E93F1E300ADF649 /* LargeItemCacheTypeTests.swift */,
16BCA36F2E4D9BA700B39E7F /* FileRepositoryTests.swift */,
Expand Down Expand Up @@ -7417,6 +7420,7 @@
351B51A526D450BC00BD2BD7 /* DateExtensionsTests.swift in Sources */,
35C05DC02BC84F5800109308 /* DiagnosticsSynchronizerTests.swift in Sources */,
B390F5BA271DDC7400B64D65 /* PurchasesDeprecation.swift in Sources */,
16EE87CE2EE75B49002AC6FE /* SynchronizedUserDefaultsTests.swift in Sources */,
57FDAABE28493A29009A48F1 /* SandboxEnvironmentDetectorTests.swift in Sources */,
57BA943128330ACA00CD5FC5 /* ConfigurationTests.swift in Sources */,
16BCA37A2E4D9C0400B39E7F /* MockSimpleNetworkService.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion Sources/Identity/CustomerInfoManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class CustomerInfoManager {
self.systemInfo = systemInfo
self.dateProvider = dateProvider

self.data = .init(.init(deviceCache: deviceCache))
self.data = .init(.init(deviceCache: deviceCache), lock: .init(.recursive))
}

@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
Expand Down
11 changes: 8 additions & 3 deletions Sources/Misc/Concurrency/Atomic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import Foundation
* A generic object that performs all write and read operations atomically.
* Use it to prevent data races when accessing an object.
*
* - Important: The closures aren't re-entrant.
* - Important: The closures aren't re-entrant unless specified during construction.
* In other words, `Atomic` instances cannot be used from within the `modify` and `withValue` closures
*
* Usage:
Expand Down Expand Up @@ -56,9 +56,9 @@ internal final class Atomic<T> {
set { modify { $0 = newValue } }
}

init(_ value: T) {
init(_ value: T, lock: Lock = Lock()) {
self._value = value
self.lock = Lock()
self.lock = lock
}

@discardableResult
Expand All @@ -78,6 +78,11 @@ internal final class Atomic<T> {

@discardableResult
func withValue<Result>(_ action: (T) throws -> Result) rethrows -> Result {
if Thread.isMainThread {
// If we're already on the main thread, execute directly to avoid deadlock.
return try action(_value)
}

return try lock.perform {
try action(_value)
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Misc/Concurrency/SynchronizedUserDefaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ internal final class SynchronizedUserDefaults {
private let atomic: Atomic<UserDefaults>

init(userDefaults: UserDefaults) {
self.atomic = .init(userDefaults)
self.atomic = .init(userDefaults, lock: .init(.recursive))
}

func read<T>(_ action: (UserDefaults) throws -> T) rethrows -> T {
Expand Down
Loading