migfabio
(Fabio)
1
Hi all, I need some guidance to understand this warning I am getting while migrating the app to Swift 6. I've enabled the Struct Concurrency Checking to Complete. I have the following SwiftUI view:
struct HolidaysListView: View {
let holidays: [Holiday]
@Binding var path: NavigationPath
var body: some View {
VStack {
GeometryReader { proxy in
let size = proxy.size
ScrollView(.horizontal) {
HStack(spacing: 0) {
ForEach(holidays) { holiday in
HolidayListViewItem(holiday: holiday, path: $path)
.padding(.horizontal)
.frame(width: size.width)
.visualEffect { content, geometryProxy in
content
.scaleEffect(scale(geometryProxy), anchor: .trailing)
.rotationEffect(rotation(geometryProxy))
.offset(x: minX(geometryProxy))
.offset(x: excessMinX(geometryProxy))
}
.zIndex(holidays.zIndex(of: holiday))
}
}
.padding(.vertical)
}
.scrollTargetBehavior(.paging)
.scrollIndicators(.hidden)
}
.aspectRatio(contentMode: .fit)
}
}
private func minX(_ proxy: GeometryProxy) -> CGFloat {
let minX = proxy.frame(in: .scrollView(axis: .horizontal)).minX
return minX < 0 ? 0 : -minX
}
private func progess(_ proxy: GeometryProxy) -> CGFloat {
let maxX = proxy.frame(in: .scrollView(axis: .horizontal)).maxX
guard let width = proxy.bounds(of: .scrollView(axis: .horizontal))?.width else {
return 0
}
let visibleCards = CGFloat(2)
return min((maxX / width) - 1, visibleCards)
}
private func scale(_ proxy: GeometryProxy) -> CGFloat {
let scaleFactor = 0.1
return 1 - (progess(proxy) * scaleFactor)
}
private func excessMinX(_ proxy: GeometryProxy) -> CGFloat {
let offset: CGFloat = 10
return progess(proxy) * offset
}
private func rotation(_ proxy: GeometryProxy) -> Angle {
let rotation: CGFloat = 5
return Angle(degrees: progess(proxy) * rotation)
}
}
And in the visualEffect modifier, I am getting 4 warnings like this:
It seems GeometryProxy is not Sendable.
I am lost on what to do here. Any feedback and explanations are much appreciated.
Andropov
(Raúl Montón)
2
By default, methods of any struct conforming to View inherit the Main Actor isolation. So here scale, rotation, minX and excessMinX are implicitly @MainActor as well.
You don't want that because visualEffect's closure is not Main Actor isolated, so attempting to call any of those methods from within said closure raises a "Call to main actor-isolated instance method 'rotation' in a synchronous nonisolated context" warning.
All you need to do is mark the methods as nonisolated:
nonisolated private func minX(_ proxy: GeometryProxy) -> CGFloat { ... }
nonisolated private func progess(_ proxy: GeometryProxy) -> CGFloat { ... }
nonisolated private func scale(_ proxy: GeometryProxy) -> CGFloat { ... }
nonisolated private func excessMinX(_ proxy: GeometryProxy) -> CGFloat { ... }
nonisolated private func rotation(_ proxy: GeometryProxy) -> Angle { ... }
By removing this implicit @MainActor isolation, these methods will be able to be called from inside visualEffect { ... }. It's safe to pass a GeometryProxy to them because you're not crossing an actor boundary by doing so.
1 Like
migfabio
(Fabio)
3
Thanks @Andropov
I appreciate the time to answer my question. Need to learn better Concurrency.
1 Like