Files
purchases-ios/Sources/Caching/InMemoryCachedObject.swift
T
NachoSoto 0bff3f65fe Sendable support (#1795)
Fixes [CSDK-379] and https://github.com/RevenueCat/purchases-ios/issues/1041#issuecomment-1206445939

[CSDK-379]: https://revenuecats.atlassian.net/browse/CSDK-379?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

### Main changes:
- `Sendable` conformances to all types that are thread-safe
- `@unchecked Sendable` for types that the compiler can't enforce, but with documentation as to why
- Made classes that aren't mocked `final` (note that this doesn't change the API, because none of these were `open` to begin with)
- Made some classes thread-safe that weren't (like `DeviceCache`)

For the non-`final` `class`es, I've actually managed to compile the SDK with all of them as `final` and `Sendable`, to make sure that making them `@unchecked Sendable` didn't hide any other issues.

### Future improvements:
- https://twitter.com/nachosoto/status/1557139992056500224?s=21&t=arWdvEzTIFANBvwqQ0vPiA
- https://twitter.com/nachosoto/status/1557141944777592832?s=21&t=arWdvEzTIFANBvwqQ0vPiA
- https://twitter.com/nachosoto/status/1557143374922059776?s=21&t=arWdvEzTIFANBvwqQ0vPiA

### Depends on:
- #1794
- #1804
- #1806
- #1807
- #1808
- #1813
- #1822
- #1823
- #1824
- #1825
- #1826
2022-08-31 13:30:38 -07:00

70 lines
1.7 KiB
Swift

//
// Copyright RevenueCat Inc. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// InMemoryCachedObject.swift
//
// Created by Joshua Liebowitz on 7/13/21.
//
import Foundation
class InMemoryCachedObject<T> {
private typealias Data = (cachedObject: T?, lastUpdated: Date?)
private let content: Atomic<Data> = .init((nil, nil))
var lastUpdatedAt: Date? {
return self.content.value.lastUpdated
}
func isCacheStale(durationInSeconds: Double) -> Bool {
return self.content.withValue {
guard let lastUpdated = $0.lastUpdated else {
return true
}
let timeSinceLastCheck = -1.0 * lastUpdated.timeIntervalSinceNow
return timeSinceLastCheck >= durationInSeconds
}
}
func clearCacheTimestamp() {
self.content.modify { $0.lastUpdated = nil }
}
func clearCache() {
self.content.modify {
$0.cachedObject = nil
$0.lastUpdated = nil
}
}
func updateCacheTimestamp(date: Date) {
self.content.modify {
$0.lastUpdated = date
}
}
func cache(instance: T) {
self.content.modify {
$0.lastUpdated = Date()
$0.cachedObject = instance
}
}
func cachedInstance() -> T? {
return self.content.value.cachedObject
}
}
// @unchecked because:
// - Class is not `final` (it's mocked). This implicitly makes subclasses `Sendable` even if they're not thread-safe.
extension InMemoryCachedObject: @unchecked Sendable {}