I have a UICollectionViewCel', an embedded UIView with a shadow and within that a UIImageView.
The following code fetches an average RGB based on the image within the imageivew (Thanks Paul Hudson)
var averageColor: UIColor? {
guard let inputImage = CIImage(image: self) else { return nil }
let extentVector = CIVector(x: inputImage.extent.origin.x, y: inputImage.extent.origin.y, z: inputImage.extent.size.width, w: inputImage.extent.size.height)
guard let filter = CIFilter(name: "CIAreaAverage", parameters: [kCIInputImageKey: inputImage, kCIInputExtentKey: extentVector]) else { return nil }
guard let outputImage = filter.outputImage else { return nil }
var bitmap = [UInt8](repeating: 0, count: 4)
let context = CIContext(options: [.workingColorSpace: kCFNull])
context.render(outputImage, toBitmap: &bitmap, rowBytes: 4, bounds: CGRect(x: 0, y: 0, width: 1, height: 1), format: .RGBA8, colorSpace: nil)
return UIColor(red: CGFloat(bitmap[0]) / 255, green: CGFloat(bitmap[1]) / 255, blue: CGFloat(bitmap[2]) / 255, alpha: CGFloat(bitmap[3]) / 255)
}
Now this is quite an expensive bit of code. Thus the idea is to pop it onto the global queue than once I have the colour to the set the shadow colour on the main queue.
To achieve this I do the following
DispatchQueue.global().async {
if let color = self.cellImageView.image?.averageColor?.cgColor {
DispatchQueue.main.async {
self.cardView.layer.shadowColor = color
}
}
}
The result is a pretty smooth scrolling action but incomes XCODES thread checker. I don't want to turn it off in the scheme settings but want to get the thread checker to ignore this syntax.
Does anybody know how to achieve this?
Thanks
The problem is that you’re accessing a property of a UIKit control from a background thread. Instead, fetch the image from the image view on the main thread. Then, once you’ve done that, you can calculate the average color on a background thread, and then dispatch the layer update back to the main thread:
guard let image = cellImageView.image else { return }
DispatchQueue.global().async {
guard let color = image.averageColor?.cgColor else { return }
DispatchQueue.main.async {
self.cardView.layer.shadowColor = color
}
}