From c486cb127400850499fd2c2b3f10e11d2478d486 Mon Sep 17 00:00:00 2001 From: NachoSoto Date: Fri, 24 Jul 2026 07:28:29 -0700 Subject: [PATCH] Adopt Swift 6 concurrency boundaries --- .../Renderers/ImageInflaterRenderer.swift | 2 +- AsyncImageView/Renderers/Renderer.swift | 2 +- AsyncImageView/Renderers/ViewRenderer.swift | 41 +++++++++++-------- AsyncImageView/SynchronousUIScheduler.swift | 2 +- 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/AsyncImageView/Renderers/ImageInflaterRenderer.swift b/AsyncImageView/Renderers/ImageInflaterRenderer.swift index 626385af..36d1268b 100644 --- a/AsyncImageView/Renderers/ImageInflaterRenderer.swift +++ b/AsyncImageView/Renderers/ImageInflaterRenderer.swift @@ -73,7 +73,7 @@ public final class ImageInflaterRenderer: RendererType { } } -public enum ImageInflaterRendererContentMode { +public enum ImageInflaterRendererContentMode: Sendable { case aspectFill case aspectFit diff --git a/AsyncImageView/Renderers/Renderer.swift b/AsyncImageView/Renderers/Renderer.swift index d45addfd..b067f1b1 100644 --- a/AsyncImageView/Renderers/Renderer.swift +++ b/AsyncImageView/Renderers/Renderer.swift @@ -11,7 +11,7 @@ import UIKit import ReactiveSwift /// Information required to produce an image -public protocol RenderDataType: Hashable { +public protocol RenderDataType: Hashable, Sendable { var size: CGSize { get } } diff --git a/AsyncImageView/Renderers/ViewRenderer.swift b/AsyncImageView/Renderers/ViewRenderer.swift index 48a9e16e..f1e474f2 100644 --- a/AsyncImageView/Renderers/ViewRenderer.swift +++ b/AsyncImageView/Renderers/ViewRenderer.swift @@ -15,8 +15,9 @@ import ReactiveSwift /// `RendererType` which generates a `UIImage` from a UIView. @available(iOS 10.0, tvOSApplicationExtension 10.0, *) -public final class ViewRenderer: RendererType { - public typealias Block = (_ data: Data) -> UIView +@MainActor +public final class ViewRenderer: @MainActor RendererType { + public typealias Block = @MainActor (_ data: Data) -> UIView private let format: UIGraphicsImageRendererFormat private let viewCreationBlock: Block @@ -49,8 +50,9 @@ public final class ViewRenderer: RendererType { } /// `RendererType` which generates a `UIImage` from a UIView. -public final class OldViewRenderer: RendererType { - public typealias Block = (_ data: Data) -> UIView +@MainActor +public final class OldViewRenderer: @MainActor RendererType { + public typealias Block = @MainActor (_ data: Data) -> UIView private let opaque: Bool private let viewCreationBlock: Block @@ -82,27 +84,32 @@ public final class OldViewRenderer: RendererType { fileprivate func createProducer( _ data: Data, - viewCreationBlock: @escaping (_ data: Data) -> UIView, - renderBlock: @escaping (UIView) -> UIImage + viewCreationBlock: @escaping @MainActor (_ data: Data) -> UIView, + renderBlock: @escaping @MainActor (UIView) -> UIImage ) -> SignalProducer { return SignalProducer { observer, lifetime in - let view = viewCreationBlock(data) - view.frame.origin = .zero - view.bounds.size = data.size - view.layoutIfNeeded() - - // Make the CA renderer wait "until all the post-commit triggers fire". - // We can't take a snapshot right away because the view has not been commited to the render server yet. - DispatchQueue.main.async { - if !lifetime.hasEnded { - observer.send(value: renderBlock(view)) - observer.sendCompleted() + MainActor.assumeIsolated { + let view = viewCreationBlock(data) + view.frame.origin = .zero + view.bounds.size = data.size + view.layoutIfNeeded() + + // Make the CA renderer wait "until all the post-commit triggers fire". + // We can't take a snapshot right away because the view has not been commited to the render server yet. + UIScheduler().schedule { + MainActor.assumeIsolated { + if !lifetime.hasEnded { + observer.send(value: renderBlock(view)) + observer.sendCompleted() + } + } } } } .start(on: UIScheduler()) } +@MainActor fileprivate func draw(view: UIView, inContext context: CGContext) { view.layer.render(in: context) } diff --git a/AsyncImageView/SynchronousUIScheduler.swift b/AsyncImageView/SynchronousUIScheduler.swift index dcecbe2a..bd050ed4 100644 --- a/AsyncImageView/SynchronousUIScheduler.swift +++ b/AsyncImageView/SynchronousUIScheduler.swift @@ -22,7 +22,7 @@ internal final class SynchronousUIScheduler: Scheduler { if Thread.isMainThread { action() } else { - DispatchQueue.main.async { + UIScheduler().schedule { if !disposable.isDisposed { action() }