Is there any state that's being read/written to in the ImageProcessing actor? If not then I don't know if you should use an actor at all unless whatever processImageData does requires exclusive execution.
As for calling that code on the background from the main actor, you need to use asyncDetached because regular async will inherit the actor from the current execution context (the MainActor in this case).
I think this is the code you're aiming for:
@MainActor
class OsuImageCache {
init() { ... }
/// Grab an image on the main thread for use in collection view cells
func image(for url: URL) -> UIImage? { }
/// Cache an image on a background thread
func cacheImage(for url: URL) async throws -> (image: UIImage?, thumbnail: UIImage?) {
let (data, _) = try await session.data(from: url)
let processTask = asyncDetached(priority: /* use whatever you want like .userInitiated or .utility */) {
return processImageData(data, for url)
}
let processedImages = await processTask.get()
try saveInFileSystem(imageData: processedImages.imageData, thumbnailImageData: processedImages.thumbnailData, for url: URL)
return (UIImage(data: processedImages.imageData), UIImage(data: processedImages.thumbnailData))
}
/// Resize images and create thumbnails
/// NOT ASYNC
func processImageData(_ data: Data, url: URL) -> (UIImage, UIImage) {
// Code that resizes the image and the thumbnail goes here. It's all inline, no completion handlers nor async calls...
...
// Finally, return
return (finalProcessedImageData, finalProcessedThumbnailData)
}
}