Skip to content

Commit 54eb385

Browse files
committed
Refactor to fix StrictConcurrency warnings
1 parent f760844 commit 54eb385

File tree

6 files changed

+132
-116
lines changed

6 files changed

+132
-116
lines changed

Sources/WaterfallGrid/Environment/GridSyle.swift

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ struct GridSyle {
1313
let spacing: CGFloat
1414
let animation: Animation?
1515

16+
@MainActor
1617
var columns: Int {
1718
#if os(OSX) || os(tvOS) || targetEnvironment(macCatalyst) || os(visionOS)
1819
return columnsInLandscape
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//
2+
// Copyright © 2024 Paolo Leonardi.
3+
//
4+
// Licensed under the MIT license. See the LICENSE file for more info.
5+
//
6+
7+
import Foundation
8+
9+
struct AnyHashableAndSendable: @unchecked Sendable, Hashable {
10+
private let wrapped: AnyHashable
11+
12+
init(_ wrapped: some Hashable & Sendable) {
13+
self.wrapped = .init(wrapped)
14+
}
15+
}

Sources/WaterfallGrid/Preference/ElementPreference.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66

77
import SwiftUI
88

9-
struct ElementPreferenceData: Equatable {
10-
let id: AnyHashable
9+
struct ElementPreferenceData: Equatable, Sendable {
10+
let id: AnyHashableAndSendable
1111
let size: CGSize
1212
}
1313

1414
struct ElementPreferenceKey: PreferenceKey {
1515
typealias Value = [ElementPreferenceData]
1616

17-
static var defaultValue: [ElementPreferenceData] = []
17+
static let defaultValue: [ElementPreferenceData] = []
1818

1919
static func reduce(value: inout [ElementPreferenceData], nextValue: () -> [ElementPreferenceData]) {
2020
value.append(contentsOf: nextValue())

Sources/WaterfallGrid/Preference/PreferenceSetter.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66

77
import SwiftUI
88

9-
struct PreferenceSetter<ID: Hashable>: View {
10-
var id: ID
9+
struct PreferenceSetter: View {
10+
var id: AnyHashableAndSendable
1111
var body: some View {
1212
GeometryReader { geometry in
1313
Color.clear
14-
.preference(key: ElementPreferenceKey.self, value: [ElementPreferenceData(id: AnyHashable(self.id), size: geometry.size)])
14+
.preference(key: ElementPreferenceKey.self, value: [ElementPreferenceData(id: self.id, size: geometry.size)])
1515
}
1616
}
1717
}

Sources/WaterfallGrid/WaterfallGrid.swift

+14-14
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import SwiftUI
88

99
/// A container that presents items of variable heights arranged in a grid.
1010
@available(iOS 13, OSX 10.15, tvOS 13, visionOS 1, watchOS 6, *)
11-
public struct WaterfallGrid<Data, ID, Content>: View where Data : RandomAccessCollection, Content : View, ID : Hashable {
11+
public struct WaterfallGrid<Data, ID, Content>: View where Data : RandomAccessCollection, Content : View, ID : Hashable & Sendable {
1212

1313
@Environment(\.gridStyle) private var style
1414
@Environment(\.scrollOptions) private var scrollOptions
@@ -20,7 +20,7 @@ public struct WaterfallGrid<Data, ID, Content>: View where Data : RandomAccessCo
2020
@State private var loaded = false
2121
@State private var gridHeight: CGFloat = 0
2222

23-
@State private var alignmentGuides = [AnyHashable: CGPoint]() {
23+
@State private var alignmentGuides = [AnyHashableAndSendable: CGPoint]() {
2424
didSet { loaded = !oldValue.isEmpty }
2525
}
2626

@@ -29,12 +29,12 @@ public struct WaterfallGrid<Data, ID, Content>: View where Data : RandomAccessCo
2929
GeometryReader { geometry in
3030
self.grid(in: geometry)
3131
.onPreferenceChange(ElementPreferenceKey.self, perform: { preferences in
32-
DispatchQueue.global(qos: .userInteractive).async {
33-
let (alignmentGuides, gridHeight) = self.alignmentsAndGridHeight(columns: self.style.columns,
34-
spacing: self.style.spacing,
35-
scrollDirection: self.scrollOptions.direction,
36-
preferences: preferences)
37-
DispatchQueue.main.async {
32+
Task.detached(priority: .userInitiated) {
33+
let (alignmentGuides, gridHeight) = await self.alignmentsAndGridHeight(columns: self.style.columns,
34+
spacing: self.style.spacing,
35+
scrollDirection: self.scrollOptions.direction,
36+
preferences: preferences)
37+
await MainActor.run {
3838
self.alignmentGuides = alignmentGuides
3939
self.gridHeight = gridHeight
4040
}
@@ -55,20 +55,20 @@ public struct WaterfallGrid<Data, ID, Content>: View where Data : RandomAccessCo
5555
self.content(element)
5656
.frame(width: self.scrollOptions.direction == .vertical ? columnWidth : nil,
5757
height: self.scrollOptions.direction == .horizontal ? columnWidth : nil)
58-
.background(PreferenceSetter(id: element[keyPath: self.dataId]))
59-
.alignmentGuide(.top, computeValue: { _ in self.alignmentGuides[element[keyPath: self.dataId]]?.y ?? 0 })
60-
.alignmentGuide(.leading, computeValue: { _ in self.alignmentGuides[element[keyPath: self.dataId]]?.x ?? 0 })
61-
.opacity(self.alignmentGuides[element[keyPath: self.dataId]] != nil ? 1 : 0)
58+
.background(PreferenceSetter(id: AnyHashableAndSendable(element[keyPath: self.dataId])))
59+
.alignmentGuide(.top, computeValue: { _ in self.alignmentGuides[AnyHashableAndSendable(element[keyPath: self.dataId])]?.y ?? 0 })
60+
.alignmentGuide(.leading, computeValue: { _ in self.alignmentGuides[AnyHashableAndSendable(element[keyPath: self.dataId])]?.x ?? 0 })
61+
.opacity(self.alignmentGuides[AnyHashableAndSendable(element[keyPath: self.dataId])] != nil ? 1 : 0)
6262
}
6363
}
6464
.animation(self.loaded ? self.style.animation : nil, value: UUID())
6565
}
6666

6767
// MARK: - Helpers
6868

69-
func alignmentsAndGridHeight(columns: Int, spacing: CGFloat, scrollDirection: Axis.Set, preferences: [ElementPreferenceData]) -> ([AnyHashable: CGPoint], CGFloat) {
69+
func alignmentsAndGridHeight(columns: Int, spacing: CGFloat, scrollDirection: Axis.Set, preferences: [ElementPreferenceData]) -> ([AnyHashableAndSendable: CGPoint], CGFloat) {
7070
var heights = Array(repeating: CGFloat(0), count: columns)
71-
var alignmentGuides = [AnyHashable: CGPoint]()
71+
var alignmentGuides = [AnyHashableAndSendable: CGPoint]()
7272

7373
preferences.forEach { preference in
7474
if let minValue = heights.min(), let indexMin = heights.firstIndex(of: minValue) {

0 commit comments

Comments
 (0)