Xamarin.Forms.Nuke: iOS native image caching for Xamarin.Forms

A binding of the Nuke iOS image caching library for Xamarin.Forms.

Get it from Github:

https://github.com/roubachof/Xamarin.Forms.Nuke

This library was heavily inspired by Jonathan Peppers GlideX implementation of the IImageViewHandler interface for Xamarin.Forms (https://github.com/jonathanpeppers/glidex).

Its goal is to provide the same kind of native implementation for iOS, achieving a complete native image caching solution for Xamarin.Forms: you don't have to change any line of your existing project, the Xamarin.Forms image source handlers will just be overridden with cache-enabled ones.

A native swift library or nothing!

If you read my previous post on the subject, you should know that I really wanted to achieve the same thing than Jonathan Peppers with GlideX.Forms on Android: a native image caching implementation for the Xamarin.Forms iOS platform:

I ended-up writing an ImageSourceHandler for FFImageLoading: https://github.com/roubachof/Xamarin.Forms.ImageSourceHandlers.

It was OK, but I wanted MOAR.

I wanted a Xamarin binding for a fancy swift native library, no less.

A new hope

Then earlier last year, it finally came out:

swiftomatic

I was so pumped, I tried it right away!
Unfortunately, this was not as "o-matic" as I thought it would be...

I really tried hard to bind Kingfisher or Nuke, but encountered a lot of issues.
In fact the biding tools are still under heavy development and not really usable for now.

So I just forgot about it...

The hope strikes back

Last week, I was procrastinating away from my .NetConf Sharpnado recording, when I stumbled upon this blog post:

https://devblogs.microsoft.com/xamarin/binding-ios-swift-libraries/

Bind a swift library in just 3 easy steps?

I was once against tempted.
It was indeed 3 easy steps, but there were also some easy sub-steps involved...
The blog post was in fact referring to the in-depth binding walkthrough here:

https://docs.microsoft.com/en-US/xamarin/ios/platform/binding-swift/walkthrough

This doc is really well-written with a lot of screenshots, a nice example, some bash commands to be executed...

And guess what?

I finally managed to bind the iOS Nuke library \o/

oui

Benchmark time!

The benchmark app is the same than in my previous post: the GlideX sample app.

I changed a bit the glidex benchmark samples to have a more fair comparison. I switched from a random distribution of the images to a deterministic one to be sure we are comparing the same data set.

I used System.Diagnostics.Process.GetCurrentProcess().WorkingSet64 to have the memory workload of the process. The value given in the results are the consumed bytes between the MainPage and the complete loading of the target page.

The tests have been made on an iPhone 7 (real device, not a simulator).

For each test:

  1. Launch iPhone 7
  2. Wait 4-5 seconds on MainPage
  3. Launch a Page
  4. Scroll till the end of page
  5. Get consumed bytes in the output window
  6. Empty caches
  7. Kill app
Page Data Type Xamarin.Forms 4.5.0.356 Xamarin.Forms.Nuke 8.4.0
GridOnlyRemotePage Remote only 248 905 728 15 073 280 (-94%)
GridPage Remote and local mix 195 035 136 15 040 512 (-92%)
ViewCellPage Remote and local mix 41 418 752 20 758 528 (-50%)
ImageCellPage Remote and local mix 27 000 832 20 611 072 (-24%)
HugeImagePage Local only 128 516 096 8 634 368 (-93%)

Comparison with FFImageLoading

Before I could successfully bind the Nuke swift library, I tried to use FFImageLoading as image source handler. You can find the older repository here:

https://github.com/roubachof/Xamarin.Forms.ImageSourceHandlers

As expected the native Nuke library outperforms FFImageLoading on every test.

Page Data Type FFImageLoading 2.4.11.982 Xamarin.Forms.Nuke 8.4.0
GridOnlyRemotePage Remote only 25 722 880 15 073 280 (-41%)
GridPage Remote and local mix 24 674 304 15 040 512 (-39%)
ViewCellPage Remote and local mix 28 852 224 (1) 20 758 528 (-28%)
ImageCellPage Remote and local mix 28 868 608 (2) 20 611 072 (-28%)
HugeImagePage Local only 10 059 776 8 634 368 (-14%)
  • (1) often fails to load first images (failed 7 times on 10)
  • (2) often fails to load some images (failed 6 times on 10)

And more importantly, it loads way faster the cells images:

View Cells test

FFImageLoading Nuke

Image Cells test

FFImageLoading Nuke