Xamarin.Nuke: a Xamarin binding for the iOS image caching library

Xamarin.Nuke: a Xamarin binding for the iOS image caching library
https://github.com/roubachof/NukeProxy

Today's guest: The one and only Cheese Baron!

I know the cheeeese since my MVVMCross days when we were binding C# code on native views like aristocrats. For me he is one of the pillar of Xamarin open source community. So I was super happy when he reached out to me on Twitter about the nuke proxy subject.

You see, Xamarin.Forms iOS platform projects were super jealous of the outstanding work done by Jonathan Peppers with GlideX on Android:

https://devblogs.microsoft.com/xamarin/glidex-fast-images-android/

So I created the iOS version of this amazing Xamarin.Forms image handler:

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

This library is built on top of a binding library of Nuke. First I didn't put the binding project on Github, but some users reached out about it, so I gladly exposed it, but with a little doc and without any CI, or nuget package...

This was the state the repo was in when I received a ping on Twitter...
And now I leave the keyboard to your Baron.

The story

In search of a fast image loading library I stumbled over Jean-Marie's Xamarin.Nuke.Forms library which looked very promising.
However, I don't use Xamarin.Forms for my projects, so I needed just the Nuke parts, without the extra forms stuff. Jean-Marie, hadn't
published any of those on NuGet. However, he did publish the code he generated the Nuke bindings from. Shortly after this discovery
I reached out to ask if I could help making a package out of it.

First, one short step back. What is Nuke? It is a image loading system. A pretty fast and fairly popular one. Nuke works on iOS, WatchOS, macOS and tvOS.
It is written in Swift and all of it is Open Source on GitHub.

The part about being written in Swift is what makes Nuke a bit tricky to create bindings for. The way this works with Xamarin Binding libraries is roughly like this:

  1. Build the swift project
  2. Prepare metadata for Xamarin Bindings
  3. Build binding library with native library + metadata
  4. Enjoy

The only way to get the metadata to pick up the classes and methods in the swift project is to annotate your swift code with @objc to generate headers the metadata understands.
In a project like Nuke this is kind of a big task to do.

What then?!

Instead you can take the approach of making a small proxy library that consumes a Swift project and exposes the important surface of that project. This is the approach taken with
the bindings for Xamarin.Nuke. Hopefully sometime in the future we will get support for creating bindings for Swift projects without having to proxy it like this.

So looking at the NukeProxy project we expose the following surface:

  • ImagePipeline - load images various ways and cache them

    • LoadImage - load image from URL into a UIImageView and optionally supply placeholders for fail scenarios
    • LoadData - load image from URL into NSData to be able to load it into for example a Skia Bitmap
  • ImageCache

    • RemoveAll - removes all cache entries
  • DataLoader

    • RemoveAllCachedResponses - removes all cached HTTP requests
  • Prefetcher - load images optimistically into cache for later use

    • StartPrefetching - provide a collection of URLs to prefetch
    • StopPrefetching
    • Pause
    • UnPause

This is all exported by annotating a fairly short Swift class with the @objc annotation to surface headers for Objective-C code to consume.

To easily upgrade the version of the Nuke library to be bound, a fairly easy to use Pipeline has been set up using GitHub Actions. How we do it is as follows:

  1. Grab defined version of Nuke from Carthage
  2. Build Nuke xcframework
  3. Build fat library of NukeProxy for Xamarin Binding to consume
  4. Run Objective Sharpie to generate metadata
  5. Build Xamarin.iOS binding library with fat library + Nuke.framework
  6. Generate NuGet package

To dial in this process I ended up trying some different things that didn't work.

  • Instead of a Fat library for the Xamarin Binding I tried with a xcarchive, this doesn't seem to work
  • Instead of getting Nuke from Carthage, I tried using Swift Package Manager and importing Nuke that way, this doesn't work as it doesn't produce Nuke.framework in the output

In the end, just use fat libraries and you will have a much better time.

Grab the latest version of Xamarin.Nuke and give it a spin!

The Sharpnado Silly Questions

The Sharpnado Silly Questions will now enter the private sphere of the contributor.

What are your top 3 best album/songs of all time?

Hard to say, this may change if you ask me some other time, but if I absolutely have to pick something like this:

  • Iron Maiden - Seventh Son of a Seventh Son
  • Opeth - Ghost Reveries
  • Gojira - L'Enfant Sauvage

What are your top 3 best movies of all time?

  • Pulp Fiction
  • The Lord of the Rings - Fellowship of the Ring
  • The Godfather

What is currently your favorite youtube video?

https://www.youtube.com/watch?v=YdFoO4DGXHw

Are you more a city, mountain, sea, or country person?

Woods or country.

What do you enjoy in life apart from coding?

Biking, walking and nerding out in different stuff.

What is your quest?

So far it has been to help people through my code in various ways

What is your favorite color?

Something around #3c26a0