Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AsyncImageView/Renderers/ImageInflaterRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public final class ImageInflaterRenderer<Renderer: RendererType>: RendererType {
}
}

public enum ImageInflaterRendererContentMode {
public enum ImageInflaterRendererContentMode: Sendable {
case aspectFill
case aspectFit

Expand Down
2 changes: 1 addition & 1 deletion AsyncImageView/Renderers/Renderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
}

Expand Down
41 changes: 24 additions & 17 deletions AsyncImageView/Renderers/ViewRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@

/// `RendererType` which generates a `UIImage` from a UIView.
@available(iOS 10.0, tvOSApplicationExtension 10.0, *)
public final class ViewRenderer<Data: RenderDataType>: RendererType {
public typealias Block = (_ data: Data) -> UIView
@MainActor
public final class ViewRenderer<Data: RenderDataType>: @MainActor RendererType {
public typealias Block = @MainActor (_ data: Data) -> UIView

private let format: UIGraphicsImageRendererFormat
private let viewCreationBlock: Block
Expand Down Expand Up @@ -49,8 +50,9 @@
}

/// `RendererType` which generates a `UIImage` from a UIView.
public final class OldViewRenderer<Data: RenderDataType>: RendererType {
public typealias Block = (_ data: Data) -> UIView
@MainActor
public final class OldViewRenderer<Data: RenderDataType>: @MainActor RendererType {
public typealias Block = @MainActor (_ data: Data) -> UIView

private let opaque: Bool
private let viewCreationBlock: Block
Expand Down Expand Up @@ -82,27 +84,32 @@

fileprivate func createProducer<Data: RenderDataType>(
_ data: Data,
viewCreationBlock: @escaping (_ data: Data) -> UIView,
renderBlock: @escaping (UIView) -> UIImage
viewCreationBlock: @escaping @MainActor (_ data: Data) -> UIView,
renderBlock: @escaping @MainActor (UIView) -> UIImage
) -> SignalProducer<UIImage, Never> {
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 {

Check failure on line 101 in AsyncImageView/Renderers/ViewRenderer.swift

View workflow job for this annotation

GitHub Actions / test

sending 'lifetime' risks causing data races
observer.send(value: renderBlock(view))

Check failure on line 102 in AsyncImageView/Renderers/ViewRenderer.swift

View workflow job for this annotation

GitHub Actions / test

sending 'observer' risks causing data races
observer.sendCompleted()
}
}
}
}
}
.start(on: UIScheduler())
}

@MainActor
fileprivate func draw(view: UIView, inContext context: CGContext) {
view.layer.render(in: context)
}
Expand Down
2 changes: 1 addition & 1 deletion AsyncImageView/SynchronousUIScheduler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal final class SynchronousUIScheduler: Scheduler {
if Thread.isMainThread {
action()
} else {
DispatchQueue.main.async {
UIScheduler().schedule {
if !disposable.isDisposed {
action()
}
Expand Down
Loading