Skip to content

refactor(mobile): cleanup image request pipeline on iOS #27481

Closed
LeLunZ wants to merge 4 commits intobugfix-27365from
refactor-ios-image-pipeline
Closed

refactor(mobile): cleanup image request pipeline on iOS #27481
LeLunZ wants to merge 4 commits intobugfix-27365from
refactor-ios-image-pipeline

Conversation

@LeLunZ
Copy link
Copy Markdown
Collaborator

@LeLunZ LeLunZ commented Apr 3, 2026

Description

While looking into #27471 I saw some opportunities to abstract a few things, which I think makes this a bit easier to work with.

Fixes:

  • isCancelled is now thread-safe and uses an UnfairLock for access.

Improvement:

  • calls the callback of the cancelled request now instantly when cancelling, as previously the thread which did the work had to call it. Now the worker only has to check isCancelled and has to exist, nothing more.

Refactoring:

  • Consolidated shared logic into ImageRequest base class (call-once callback, cancellation, image conversion)
  • Unified request dictionary management into generic RequestRegistry (replaces two different locking strategies in Remote and Local Implementation)
  • Wrapped os_unfair_lock in heap-allocating UnfairLock to avoid Swift copy-in/copy-out risk (claude-code did this)
  • Removed unnecessary assetQueue: NSCache is already thread-safe:
    • You can add, remove, and query items in the cache from different threads without having to lock the cache yourself.

  • Removed cancelQueue: callback is nil-guarded and onCancel implementations are idempotent, so no serialization needed

@mertalev if you find the UnfairLock unnecessary I can also remove it, I just included it because I found references which said not to use one 10 years ago :)

How Has This Been Tested?

  • in the simulator scrolling through timeline/opening images
  • would still appreciate an in-depth review

Checklist:

  • I have carefully read CONTRIBUTING.md
  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation if applicable
  • I have no unrelated changes in the PR.
  • I have confirmed that any new dependencies are strictly necessary.
  • I have written tests for new code (if applicable)
  • I have followed naming conventions/patterns in the surrounding code
  • All code in src/services/ uses repositories implementations for database calls, filesystem operations, etc.
  • All code in src/repositories/ is pretty basic/simple and does not have any immich specific logic (that belongs in src/services/)

Please describe to which degree, if any, an LLM was used in creating this pull request.

Claude Code did the UnfairLock implementation, and part of this description.

@LeLunZ LeLunZ requested a review from mertalev April 3, 2026 01:21
@LeLunZ LeLunZ requested a review from shenlong-tanwen as a code owner April 3, 2026 01:21
@immich-push-o-matic
Copy link
Copy Markdown

Label error. Requires exactly 1 of: changelog:.*. Found: 📱mobile. A maintainer will add the required label.

1 similar comment
@immich-push-o-matic
Copy link
Copy Markdown

Label error. Requires exactly 1 of: changelog:.*. Found: 📱mobile. A maintainer will add the required label.

@LeLunZ LeLunZ changed the title Refactor ios image pipeline refactor(mobile): cleanup image request pipeline on iOS Apr 3, 2026
Copy link
Copy Markdown
Member

@mertalev mertalev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is making a lot of sweeping changes and the abstraction makes it harder to see that the behavior is the same. I'd prefer smaller, more targeted PRs for this code.

if request.isCancelled {
return completion(ImageProcessing.cancelledResult)
}
if request.isCancelled { return }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does it respond to Pigeon in this case?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always in the cancel method of the request.

Comment on lines +154 to 161
if let cached = assetCache.object(forKey: assetId as NSString) {
return cached
}

guard let asset = PHAsset.fetchAssets(withLocalIdentifiers: [assetId], options: Self.fetchOptions).firstObject
else { return nil }
assetQueue.async { assetCache.setObject(asset, forKey: assetId as NSString) }
assetCache.setObject(asset, forKey: assetId as NSString)
return asset
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dictionary isn't thread-safe.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn’t the NSCache thread save, the docs are linked above?

Comment on lines +10 to +11
lock.lock()
defer { lock.unlock() }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need a lock?

return _isCancelled
}

init(callback: @escaping (Result<[String: Int64]?, any Error>) -> Void) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably shouldn't be nullable.

Comment thread mobile/ios/Runner/Images/ImageRequest.swift
Comment thread mobile/ios/Runner/Images/UnfairLock.swift
@LeLunZ
Copy link
Copy Markdown
Collaborator Author

LeLunZ commented Apr 3, 2026

Will see what I can do about splitting this into smaller PRs.

@LeLunZ
Copy link
Copy Markdown
Collaborator Author

LeLunZ commented Apr 3, 2026

Replaced with #27486 #27489

@LeLunZ LeLunZ closed this Apr 3, 2026
@LeLunZ LeLunZ deleted the refactor-ios-image-pipeline branch April 7, 2026 14:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants