mirror of
https://github.com/RevenueCat/purchases-ios
synced 2026-11-09 22:35:56 +05:45
When compiling with Xcode 16, we started throwing a bunch of new warnings. Here's a list and explanation of each: - The most common one was needing to explicitly restate the @unchecked Sendable conformance from a parent class. - There were a couple switches where a new entry was added in tvOS but only for iOS 18, and needed to add it to make it exhaustive. - There we a couple of places where we were adding a protocol conformance to a class from a different module e.g. extension DispatchTimeInterval: Comparable. This is considered unsafe now because the owners of the module could add the conformance later. Solved by removing the conformance which wasn't being used widely in the codebase, only in tests. - Finally there was a class where we were capturing SKRequest and SKProductsRequest instances in a sendable block, but only to either log something, or use them as dictionary key, so I just made the classes Sendable (with the new @retroactice attribute because they belong to a different module)
107 lines
3.8 KiB
Swift
107 lines
3.8 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
|
|
//
|
|
// DispatchTimeInterval+Extensions.swift
|
|
//
|
|
// Created by Nacho Soto on 12/2/21.
|
|
|
|
// swiftlint:disable identifier_name
|
|
import Foundation
|
|
|
|
extension DispatchTimeInterval {
|
|
|
|
/// Creates a `DispatchTimeInterval` from a `TimeInterval` with millisecond precision.
|
|
init(_ timeInterval: TimeInterval) {
|
|
self = .milliseconds(Int(timeInterval * 1000))
|
|
}
|
|
|
|
static func minutes(_ minutes: Int) -> Self {
|
|
precondition(minutes >= 0, "Minutes must be positive: \(minutes)")
|
|
|
|
return .seconds(minutes * 60)
|
|
}
|
|
|
|
static func hours(_ hours: Int) -> Self {
|
|
precondition(hours >= 0, "Hours must be positive: \(hours)")
|
|
|
|
return .seconds(hours * 60 * 60)
|
|
}
|
|
|
|
static func days(_ days: Int) -> Self {
|
|
precondition(days >= 0, "Days must be positive: \(days)")
|
|
|
|
return Self.hours(days * 24)
|
|
}
|
|
|
|
/// `DispatchTimeInterval` can only be used by specifying a unit of time.
|
|
/// This allows us to easily convert any `DispatchTimeInterval` into nanoseconds.
|
|
/// - Important: It's likely that `x * 1_000_000_000` can't be represented in 32 bits.
|
|
var nanoseconds: UInt64 {
|
|
switch self {
|
|
case let .seconds(s): return UInt64(s) * UInt64(1_000_000_000)
|
|
case let .milliseconds(ms): return UInt64(ms) * UInt64(1_000_000)
|
|
case let .microseconds(ms): return UInt64(ms) * UInt64(1000)
|
|
case let .nanoseconds(ns): return UInt64(ns)
|
|
case .never: return 0
|
|
@unknown default: fatalError("Unknown value: \(self)")
|
|
}
|
|
}
|
|
|
|
/// - Note: this returns `Int`, so it might lose precision for `.milliseconds` and `.microseconds`.
|
|
var milliseconds: Int {
|
|
switch self {
|
|
case let .seconds(s): return s * 1_000
|
|
case let .milliseconds(ms): return ms
|
|
case let .microseconds(ms): return Int((Double(ms) / 1_000).rounded())
|
|
case let .nanoseconds(ns): return Int((Double(ns) / 1_000_000).rounded())
|
|
case .never: return 0
|
|
@unknown default: fatalError("Unknown value: \(self)")
|
|
}
|
|
}
|
|
|
|
/// `DispatchTimeInterval` can only be used by specifying a unit of time.
|
|
/// This allows us to easily convert any `DispatchTimeInterval` into seconds.
|
|
var seconds: Double {
|
|
switch self {
|
|
case let .seconds(seconds): return Double(seconds)
|
|
case let .milliseconds(ms): return Double(ms) / 1_000
|
|
case let .microseconds(ms): return Double(ms) / 1_000_000
|
|
case let .nanoseconds(ns): return Double(ns) / 1_000_000_000
|
|
case .never: return 0
|
|
@unknown default: fatalError("Unknown value: \(self)")
|
|
}
|
|
}
|
|
|
|
var days: Double {
|
|
return self.seconds / (60 * 60 * 24)
|
|
}
|
|
|
|
}
|
|
|
|
// swiftlint:enable identifier_name
|
|
|
|
func + (lhs: DispatchTimeInterval, rhs: DispatchTimeInterval) -> DispatchTimeInterval {
|
|
// Note: `DispatchTimeInterval` uses `Int` for nanoseconds, which might overflow in 32 bits
|
|
// This loses some precision by using milliseconds, but avoids potential overflows.
|
|
return .milliseconds(lhs.milliseconds + rhs.milliseconds)
|
|
}
|
|
|
|
func - (lhs: DispatchTimeInterval, rhs: DispatchTimeInterval) -> DispatchTimeInterval {
|
|
// Note: `DispatchTimeInterval` uses `Int` for nanoseconds, which might overflow in 32 bits
|
|
// This loses some precision by using milliseconds, but avoids potential overflows.
|
|
return .milliseconds(lhs.milliseconds - rhs.milliseconds)
|
|
}
|
|
|
|
#if swift(<5.9)
|
|
// `DispatchTimeInterval` is not `Sendable` as of Swift 5.8.
|
|
// Its conformance is safe since it only represents data
|
|
// See https://github.com/apple/swift/issues/65044
|
|
extension DispatchTimeInterval: @unchecked Sendable {}
|
|
#endif
|