From f6a99602e9396e0381f94ae7e0ec350584660001 Mon Sep 17 00:00:00 2001 From: mertalev <101130780+mertalev@users.noreply.github.com> Date: Wed, 10 Sep 2025 15:01:45 -0400 Subject: [PATCH] separate asset and thumbnail concurrency --- mobile/ios/Runner/Images/ThumbnailsImpl.swift | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/mobile/ios/Runner/Images/ThumbnailsImpl.swift b/mobile/ios/Runner/Images/ThumbnailsImpl.swift index 452ca62377..4de45ae09b 100644 --- a/mobile/ios/Runner/Images/ThumbnailsImpl.swift +++ b/mobile/ios/Runner/Images/ThumbnailsImpl.swift @@ -40,7 +40,8 @@ class ThumbnailApiImpl: ThumbnailApi { private static let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue).rawValue private static var requests = [Int64: Request]() private static let cancelledResult = Result<[String: Int64], any Error>.success([:]) - private static let concurrencySemaphore = DispatchSemaphore(value: ProcessInfo.processInfo.activeProcessorCount * 2) + private static let assetConcurrencySemaphore = DispatchSemaphore(value: ProcessInfo.processInfo.activeProcessorCount * 2) + private static let thumbnailConcurrencySemaphore = DispatchSemaphore(value: ProcessInfo.processInfo.activeProcessorCount / 2 + 1) private static let assetCache = { let assetCache = NSCache() assetCache.countLimit = 10000 @@ -82,22 +83,19 @@ class ThumbnailApiImpl: ThumbnailApi { return completion(Self.cancelledResult) } - Self.concurrencySemaphore.wait() - defer { - Self.concurrencySemaphore.signal() - } - - if request.isCancelled { - return completion(Self.cancelledResult) - } - - guard let asset = Self.requestAsset(assetId: assetId) + guard let asset = Self.requestAsset(request: request, assetId: assetId) else { + if request.isCancelled { + return completion(Self.cancelledResult) + } Self.removeRequest(requestId: requestId) completion(.failure(PigeonError(code: "", message: "Could not get asset data for \(assetId)", details: nil))) return } + Self.thumbnailConcurrencySemaphore.wait() + defer { Self.thumbnailConcurrencySemaphore.signal() } + if request.isCancelled { return completion(Self.cancelledResult) } @@ -187,17 +185,25 @@ class ThumbnailApiImpl: ThumbnailApi { guard let request = requests.removeValue(forKey: requestId) else { return } request.isCancelled = true guard let item = request.workItem else { return } + item.cancel() if item.isCancelled { cancelQueue.async { request.callback(Self.cancelledResult) } } } } - private static func requestAsset(assetId: String) -> PHAsset? { + private static func requestAsset(request: Request, assetId: String) -> PHAsset? { var asset: PHAsset? assetQueue.sync { asset = assetCache.object(forKey: assetId as NSString) } if asset != nil { return asset } + Self.assetConcurrencySemaphore.wait() + defer { Self.assetConcurrencySemaphore.signal() } + + if request.isCancelled { + return nil + } + guard let asset = PHAsset.fetchAssets(withLocalIdentifiers: [assetId], options: Self.fetchOptions).firstObject else { return nil } assetQueue.async { assetCache.setObject(asset, forKey: assetId as NSString) }