Skip to content

Commit 1b703f6

Browse files
authored
Add Swift 6 support (#34)
1 parent 7aff8d1 commit 1b703f6

File tree

6 files changed

+74
-40
lines changed

6 files changed

+74
-40
lines changed

Package.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// swift-tools-version:5.7
2-
// The swift-tools-version declares the minimum version of Swift required to build this package.
32

43
import PackageDescription
54

[email protected]

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// swift-tools-version:6.0
2+
3+
import PackageDescription
4+
5+
let package = Package(
6+
name: "NetworkImage",
7+
platforms: [
8+
.macOS(.v11),
9+
.iOS(.v14),
10+
.tvOS(.v14),
11+
.watchOS(.v7),
12+
],
13+
products: [
14+
.library(name: "NetworkImage", targets: ["NetworkImage"])
15+
],
16+
dependencies: [],
17+
targets: [
18+
.target(name: "NetworkImage"),
19+
.testTarget(
20+
name: "NetworkImageTests",
21+
dependencies: ["NetworkImage"]
22+
),
23+
]
24+
)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Foundation
22

3-
struct ImageSource: Hashable {
3+
struct ImageSource: Hashable, Sendable {
44
let url: URL
55
let scale: CGFloat
66
}

Sources/NetworkImage/NetworkImage.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,6 @@ public struct NetworkImage<Content>: View where Content: View {
7979
private let transaction: Transaction
8080
private let content: (NetworkImageState) -> Content
8181

82-
private var environment: NetworkImageModel.Environment {
83-
.init(transaction: self.transaction, imageLoader: self.imageLoader)
84-
}
85-
8682
/// Loads and displays an image from the specified URL using
8783
/// a default placeholder until the image loads.
8884
///
@@ -168,15 +164,19 @@ public struct NetworkImage<Content>: View where Content: View {
168164

169165
public var body: some View {
170166
if #available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) {
171-
self.content(self.model.state.image)
172-
.task(id: self.source) {
173-
await self.model.onAppear(source: self.source, environment: self.environment)
167+
self.content(model.image)
168+
.task(id: source) {
169+
model.imageLoaderChanged(imageLoader)
170+
model.transactionChanged(transaction)
171+
await model.sourceChanged(source)
174172
}
175173
} else {
176-
self.content(self.model.state.image)
174+
self.content(model.image)
177175
.modifier(
178-
TaskModifier(id: self.source) {
179-
await self.model.onAppear(source: self.source, environment: self.environment)
176+
TaskModifier(id: source) { @MainActor in
177+
model.imageLoaderChanged(imageLoader)
178+
model.transactionChanged(transaction)
179+
await model.sourceChanged(source)
180180
}
181181
)
182182
}

Sources/NetworkImage/NetworkImageCache.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import CoreGraphics
22
import Foundation
33

44
/// A type that temporarily stores images in memory, keyed by the URL from which they were loaded.
5-
public protocol NetworkImageCache: AnyObject, Sendable {
5+
public protocol NetworkImageCache: AnyObject {
66
/// Returns the image associated with a given URL.
77
func image(for url: URL) -> CGImage?
88

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,56 @@
11
import SwiftUI
22

3-
final class NetworkImageModel: ObservableObject {
4-
struct Environment {
5-
let transaction: Transaction
6-
let imageLoader: NetworkImageLoader
7-
}
3+
@MainActor final class NetworkImageModel: ObservableObject {
4+
@Published private(set) var source: ImageSource?
5+
@Published private(set) var image: NetworkImageState = .empty
86

9-
struct State: Equatable {
10-
var source: ImageSource?
11-
var image: NetworkImageState = .empty
12-
}
7+
private var transaction = Transaction()
8+
private var imageLoader: NetworkImageLoader = DefaultNetworkImageLoader.shared
139

14-
@Published private(set) var state: State = .init()
10+
// MARK: Actions
1511

16-
@MainActor func onAppear(source: ImageSource?, environment: Environment) async {
17-
guard source != self.state.source else { return }
12+
func sourceChanged(_ source: ImageSource?) async {
13+
guard source != self.source else { return }
1814

19-
guard let source else {
20-
self.state = .init()
21-
return
15+
self.source = source
16+
17+
if let source {
18+
await loadImage(source: source)
2219
}
20+
}
2321

24-
self.state.source = source
22+
func transactionChanged(_ transaction: Transaction) {
23+
self.transaction = transaction
24+
}
2525

26-
let image: NetworkImageState
26+
func imageLoaderChanged(_ imageLoader: NetworkImageLoader) {
27+
self.imageLoader = imageLoader
28+
}
2729

28-
do {
29-
let cgImage = try await environment.imageLoader.image(from: source.url)
30-
image = .success(
31-
image: .init(decorative: cgImage, scale: source.scale),
30+
private func loadImageFinished(_ cgImage: CGImage, scale: CGFloat) {
31+
withTransaction(transaction) {
32+
self.image = .success(
33+
image: Image(decorative: cgImage, scale: scale),
3234
idealSize: CGSize(
33-
width: CGFloat(cgImage.width) / source.scale,
34-
height: CGFloat(cgImage.height) / source.scale
35+
width: CGFloat(cgImage.width) / scale,
36+
height: CGFloat(cgImage.height) / scale
3537
)
3638
)
37-
} catch {
38-
image = .failure
3939
}
40+
}
41+
42+
private func loadImageFailed(_: Error) {
43+
self.image = .failure
44+
}
4045

41-
withTransaction(environment.transaction) {
42-
self.state.image = image
46+
// MARK: Effects
47+
48+
private func loadImage(source: ImageSource) async {
49+
do {
50+
let cgImage = try await imageLoader.image(from: source.url)
51+
loadImageFinished(cgImage, scale: source.scale)
52+
} catch {
53+
loadImageFailed(error)
4354
}
4455
}
4556
}

0 commit comments

Comments
 (0)