diff --git a/AsyncImageView/Renderers/ImageInflaterRenderer.swift b/AsyncImageView/Renderers/ImageInflaterRenderer.swift index 626385a..36d1268 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 d45addf..b067f1b 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 48a9e16..f1e474f 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 dcecbe2..bd050ed 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() }