What’s the first class way to use PhotoKit to reimplement a high performance photo grid? We’ve been using a LazyVGrid and the photos caching manager, but are never able to hit the holy trinity (60hz, efficient memory footprint, minimal flashes of placeholder/empty cells)
A few things. It sounds like you're using the
PHCachingImageManager
already, which is definitely recommended.One kind of specific note there—you want to use that to get media content delivered before you need to display it. So, for example, let's say you're showing a large grid of photos. You can be prefetching before and after, in expectation that the user's going to scroll. Or, if you're in a one-up situation, prefetching left and right so that you know the user is likely going to swipe, and you can quickly deliver those images to the screen and cache them.
Another thing you should really make sure you're doing is specifying the size you need for the grid size. For example, if your app supports showing a smaller grid of photos, ensure that you're only requesting that size—as a lot of optimizations are done to deliver that size based on whatever intermediates we have on disk.
Also, be sure you're setting specific options:PHVideoRequestOptions.deliveryMode = .fastFormat
PHImageRequestOptions.deliveryMode = .fastFormat
PHImageRequestOptions.resizeMode = .fast
As the name implies, this is for getting images fast. Definitely look at the headers and docs for all of these, because there's a lot of options you can fine-tune depending on exactly what UI you're trying to provide.
I think Instruments is actually a really great tool to help you understand where the slowdown is coming from. Once you have a better understanding of what's actually throttling things, you can apply more targeted optimizations.
Another suggestion to look into: when you're using SwiftUI—SwiftUI views themselves are super lightweight—but if you have hundreds or thousands of them and they all have to do their own updates, those updates can potentially slow things down.
So maybe try to use Instruments to understand if you have unnecessary state updates. Making sure you can either consolidate those state updates or avoid them altogether can be really helpful.And in addition to requesting the target size of the thumbnail itself, sometimes it might be worth making a tradeoff by requesting a slightly smaller size than the actual thumbnail. For example, if the thumbnail size is 400×400 pixels, it might be OK in your use case to request a 300×300 image. Sometimes you can get performance improvements this way as well.
Even for us, we constantly have to make those kinds of tradeoffs. Depending on the use case, we may request high-resolution or low-resolution images just to balance different things.And the last suggestion I have: when working with a really large number of photos, try to offload as much processing as possible to a background thread. That way, at least the UI itself is responsive. You can do all the pre-caching and loading in the background so it doesn't slow down user interaction while the grid is active.
Regarding AVCaptureVideoPreviewLayer
in SwiftUI:
“Yeah, that’s totally fine. You can use an
AVCaptureVideoPreviewLayer
inside aUIViewRepresentable
. Whether you’re using UIKit or AppKit, you should get equivalent performance. You’re not doing anything wrong by embedding it that way—don’t worry.”
Regarding tone-mapping HDR content between HDR and SDR (i.e. one-up and thumbnail)
“This year, there’s a new system tone mapper built into the OS. Major frameworks—including Core Image, ImageKit, Core Animation, and even Core Graphics—now support it.
For example, there’s a
CISystemToneMapper
you can call. Core Animation also has apreferredDynamicRange
property onCALayer
.Each framework offers a way to tone map your output depending on your goals. You can choose between three modes:
high
: Preserve full HDR detail—use this when you want the full range of brightness shown.constrained
: A more subtle HDR effect—brightness is limited.standard
: Tone maps HDR to SDR. If the image is HDR, the system will tone map it for SDR display using an excellent internal tone mapper.
Even UIImageView
, NSImageView
, and SwiftUI.Image
now support this preferredDynamicRange
property.”
Regarding feeding images into ML models for analysis
“Some learnings over the years that we've had: they're often pretty sensitive about what size of image you're feeding into the model.
Naively, you might think, ‘Oh, I want the biggest image possible—that'll give the model the best chance of finding whatever's inside.’ But it actually depends, for example, on what size image the model was trained on. You often want to feed in images of that specific size.
Also, if you're doing this on large photo libraries, it's much more efficient if you request smaller images to feed into your models. You don’t need the original—you can request lower-resolution versions much faster.
So that’s just something to take into consideration if you’re doing custom photo analysis and ML models for image understanding.”