[ad_1]
I’ve a undertaking that turns views I create within the undertaking into Pictures then takes the pngImageData of these views and uploads it as Pictures to my server. All of it takes place with out displaying the views being generated and works terrifically. Nonetheless I would really like to have the ability to generate hundreds of those pictures at a time. Presently I name the next View extension
func getDataForFBS(width: CGFloat, top: CGFloat, _ completion: @escaping (Knowledge?) -> Void) {
let dimension = CGSize(width: width, top: top)
let controller = UIHostingController(rootView: self.body(width: dimension.width, top: dimension.top))
controller.view.bounds = CGRect(origin: .zero, dimension: dimension.making use of(.init(scaleX: 1.1, y: 1.1)))
controller.view.backgroundColor = UIColor.clear
completion(controller.view?.getImageFromCurrentContext()?.pngData())
}
which converts the View to a UIView earlier than utilizing this UIView extension
func getImageFromCurrentContext(bounds: CGRect? = nil) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(bounds?.dimension ?? self.bounds.dimension, false, 0.0)
self.drawHierarchy(in: bounds ?? self.bounds, afterScreenUpdates: true)
guard let currentImage = UIGraphicsGetImageFromCurrentImageContext() else {
return nil
}
UIGraphicsEndImageContext()
return currentImage
}
which passes again a UIImage to name .pngData()
on within the first extensions completion which I then add to my sever if the end result shouldn’t be nil.
This works nice if I solely cross in a couple of Views at a time, nevertheless it hangs the Foremost thread and inevitably crashes the complete utility if I cross in additional than about 200 without delay. I’ve tried wrapping the loop performing this in a Process
, a persistent containers performBackgroundTask
in addition to a plain previous DispatchQueue.world(qos: .userInitiated).async()
nevertheless my getImageFromCurrentContext
UIView extension calls self.drawHierarchy
which may solely be carried out on the Foremost UI thread.
I discovered this UIView extension on-line that doesn’t require the Foremost UI thread
func asImageAsync(dimension: CGSize? = nil) -> UIImage {
let format = UIGraphicsImageRendererFormat()
format.scale = 1
return UIGraphicsImageRenderer(dimension: dimension ?? self.bounds.dimension, format: format).picture { context in
layer.render(in: context.cgContext)
}
}
because it replaces self.drawHierarchy
with that layer.render
line which iOS doesn’t appear to thoughts being known as from a background thread. This works nice if I name it from the principle thread and can show the UIImage I make from the info simply tremendous. Nonetheless, if I thread out the method, it completes virtually instantly and though all of the file situations are created on my server and present an affordable file dimension for every, the precise picture is non-existent and I find yourself with a ton of clean pictures.
Is there any approach to get pngImageData from a whole bunch of SwiftUI views asynchronously? As I discussed I am not really displaying the views simply; instantiating an occasion of every one after the other passing in a contemporary fixed that determines what the view shows then, calling getDataForFBS
on every and pushing the end result as much as my server if it isn’t nil. I assumed as a result of I do not really present every view this might be straightforward to perform with out the usage of the UI thread, however I’ve been making an attempt for days now and have but to search out or work out an answer.
[ad_2]