refactor(mobile): IOS replace DispatchQueue + DispatchSemaphore with OperationQueue for image processing (#27471)

refactor: replace DispatchQueue + DispatchSemaphore with OperationQueue for image processing
This commit is contained in:
Luis Nachtigall 2026-04-05 22:11:02 +02:00 committed by GitHub
parent 196307bca5
commit 6fcf651d76
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 15 additions and 22 deletions

View File

@ -1,7 +1,12 @@
import Foundation
enum ImageProcessing {
static let queue = DispatchQueue(label: "thumbnail.processing", qos: .userInitiated, attributes: .concurrent)
static let semaphore = DispatchSemaphore(value: ProcessInfo.processInfo.activeProcessorCount * 2)
static let queue = {
let q = OperationQueue()
q.name = "thumbnail.processing"
q.qualityOfService = .userInitiated
q.maxConcurrentOperationCount = ProcessInfo.processInfo.activeProcessorCount * 2
return q
}()
static let cancelledResult = Result<[String: Int64]?, any Error>.success(nil)
}

View File

@ -4,7 +4,7 @@ import MobileCoreServices
import Photos
class LocalImageRequest {
weak var workItem: DispatchWorkItem?
weak var operation: Operation?
var isCancelled = false
let callback: (Result<[String: Int64]?, any Error>) -> Void
@ -50,7 +50,7 @@ class LocalImageApiImpl: LocalImageApi {
}()
func getThumbhash(thumbhash: String, completion: @escaping (Result<[String : Int64], any Error>) -> Void) {
ImageProcessing.queue.async {
ImageProcessing.queue.addOperation {
guard let data = Data(base64Encoded: thumbhash)
else { return completion(.failure(PigeonError(code: "", message: "Invalid base64 string: \(thumbhash)", details: nil)))}
@ -66,16 +66,7 @@ class LocalImageApiImpl: LocalImageApi {
func requestImage(assetId: String, requestId: Int64, width: Int64, height: Int64, isVideo: Bool, preferEncoded: Bool, completion: @escaping (Result<[String: Int64]?, any Error>) -> Void) {
let request = LocalImageRequest(callback: completion)
let item = DispatchWorkItem {
if request.isCancelled {
return completion(ImageProcessing.cancelledResult)
}
ImageProcessing.semaphore.wait()
defer {
ImageProcessing.semaphore.signal()
}
let operation = BlockOperation {
if request.isCancelled {
return completion(ImageProcessing.cancelledResult)
}
@ -180,9 +171,9 @@ class LocalImageApiImpl: LocalImageApi {
}
}
request.workItem = item
request.operation = operation
Self.add(requestId: requestId, request: request)
ImageProcessing.queue.async(execute: item)
ImageProcessing.queue.addOperation(operation)
}
func cancelRequest(requestId: Int64) {
@ -201,8 +192,8 @@ class LocalImageApiImpl: LocalImageApi {
requestQueue.async {
guard let request = requests.removeValue(forKey: requestId) else { return }
request.isCancelled = true
guard let item = request.workItem else { return }
if item.isCancelled {
guard let operation = request.operation else { return }
if operation.isCancelled {
cancelQueue.async { request.callback(ImageProcessing.cancelledResult) }
}
}

View File

@ -73,10 +73,7 @@ class RemoteImageApiImpl: NSObject, RemoteImageApi {
return request.completion(.failure(PigeonError(code: "", message: "No data received", details: nil)))
}
ImageProcessing.queue.async {
ImageProcessing.semaphore.wait()
defer { ImageProcessing.semaphore.signal() }
ImageProcessing.queue.addOperation {
if request.isCancelled {
return request.completion(ImageProcessing.cancelledResult)
}