Skip to content

Resolve complete strict concurrency issues #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 28, 2024
Merged
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
6 changes: 3 additions & 3 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
"package": "Etcetera",
"repositoryURL": "https://github.com/jaredsinclair/etcetera",
"state": {
"branch": "master",
"revision": "a2ea700f45a94ad6055eca2381eb3e65b8bc1018",
"version": null
"branch": null,
"revision": "3dc4efd2d72bc6bb857c0d7d801e913935ce325c",
"version": "3.0.0"
}
}
]
Expand Down
10 changes: 7 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,24 @@ import PackageDescription
let package = Package(
name: "ImageCache",
platforms: [
.iOS(.v13), .tvOS(.v13)
.iOS("17"), .tvOS("17")
],
products: [
.library(name: "ImageCache", targets: ["ImageCache"])
],
dependencies: [
.package(url: "https://github.com/jaredsinclair/etcetera", .branch("master"))
.package(url: "https://github.com/jaredsinclair/etcetera", .upToNextMajor(from: "3.0.0"))
],
targets: [
.target(
name: "ImageCache",
dependencies: [
"Etcetera"
]),
]
// Uncomment to enable complete strict concurrency checking. In a
// future update, it would be handy if this were scriptable in CI:
// swiftSettings: [ .unsafeFlags(["-Xfrontend", "-strict-concurrency=complete"]) ]
),
.testTarget(name: "ImageCacheTests",
dependencies: [
"ImageCache"
Expand Down
13 changes: 11 additions & 2 deletions Sources/ImageCache/DeferredValue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@
// Copyright © 2020 Nice Boy LLC. All rights reserved.
//

final class DeferredValue<T> {
var value: T?
import Etcetera

final class DeferredValue<T>: Sendable {

var value: T? {
get { _value.current }
set { _value.current = newValue }
}

private let _value = Protected<T?>(nil)

}
2 changes: 1 addition & 1 deletion Sources/ImageCache/DownloadResult.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Foundation
/// Communicates to `ImageCache` whether the result of a download operation was
/// that a new file was freshly downloaded, or whether a previously-downloaded
/// file was able to be used.
enum DownloadResult {
enum DownloadResult: Sendable {

/// A fresh file was downloaded and is available locally at a file URL.
case fresh(URL)
Expand Down
24 changes: 18 additions & 6 deletions Sources/ImageCache/Format.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import Etcetera
extension ImageCache {

/// Describes the format options to be used when processing a source image.
public enum Format {
public enum Format: Sendable {

// MARK: Typealiases

Expand Down Expand Up @@ -64,7 +64,15 @@ extension ImageCache {
/// - parameter contentScale: The number of pixels per point, which is
/// used to reckon the output image size relative to the requested
/// `size`. Pass `0` to use the native defaults for the current device.
case scaled(size: CGSize, mode: ContentMode, bleed: CGFloat, opaque: Bool, cornerRadius: CGFloat, border: Border?, contentScale: ContentScale)
case scaled(
size: CGSize,
mode: ContentMode = .scaleAspectFill,
bleed: CGFloat = 0,
opaque: Bool = false,
cornerRadius: CGFloat = 0,
border: Border? = nil,
contentScale: ContentScale = 0
)

/// Scale the source image and crop it to an elliptical shape. The
/// resulting image will have transparent contents in the corners.
Expand All @@ -77,7 +85,11 @@ extension ImageCache {
/// - parameter contentScale: The number of pixels per point, which is
/// used to reckon the output image size relative to the requested
/// `size`. Pass `0` to use the native defaults for the current device.
case round(size: CGSize, border: Border?, contentScale: ContentScale)
case round(
size: CGSize,
border: Border? = nil,
contentScale: ContentScale = 0
)

/// Draw the source image using a developer-supplied formatting block.
///
Expand All @@ -92,7 +104,7 @@ extension ImageCache {
/// image. The developer does not need to cache the returned image.
/// ImageCache will cache the result in the same manner as images drawn
/// using the other formats.
case custom(editKey: String, block: (ImageCache.Image) -> ImageCache.Image)
case custom(editKey: String, block: @Sendable (ImageCache.Image) -> ImageCache.Image)

}

Expand All @@ -105,7 +117,7 @@ extension ImageCache {
extension ImageCache.Format {

/// Platform-agnostic analogue to UIView.ContentMode
public enum ContentMode {
public enum ContentMode: Sendable {

/// Contents scaled to fill with fixed aspect ratio. Some portion of
/// the content may be clipped.
Expand All @@ -126,7 +138,7 @@ extension ImageCache.Format {
extension ImageCache.Format {

/// Border styles you can use when drawing a scaled or round image format.
public enum Border: Hashable {
public enum Border: Hashable, Sendable {

case hairline(ImageCache.Color)

Expand Down
4 changes: 2 additions & 2 deletions Sources/ImageCache/GCD.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@

import Foundation

func onMain(_ block: @escaping () -> Void) {
func onMain(_ block: @escaping @Sendable @MainActor () -> Void) {
DispatchQueue.main.async { block() }
}

func deferred(on queue: OperationQueue, block: @escaping () -> Void) {
func deferred(on queue: OperationQueue, block: @escaping @Sendable () -> Void) {
onMain { queue.addOperation(block) }
}
28 changes: 28 additions & 0 deletions Sources/ImageCache/ImageCache+Concurrency.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Foundation

extension ImageCache {

/// Equivalent to `image(from:format:completion:)` but as `async`.
public func image(
from url: URL,
format: Format = .original
) async -> Image? {
await image(from: .url(url), format: format)
}

/// Equivalent to `image(from:format:completion:)` but as `async`.
public func image(
from source: OriginalImageSource,
format: Format = .original
) async -> Image? {
if let cached = memoryCachedImage(from: source, format: format) {
return cached
}
return await withCheckedContinuation { (continuation: CheckedContinuation<Image?, Never>) in
self.image(from: source, format: format, completion: { image in
continuation.resume(returning: image)
})
}
}

}
Loading