Reduce share extension crashes from your app with this one weird trick!
My app Close-up lets people capture daily selfies and create time lapse videos and animated GIFs from them. Naturally, the ability to share these photos, videos, and GIFs is core functionality the app provides. I’m a big believer in UIActivityViewController
(aka the “share sheet”), so that’s what powers sharing in Close-up and my other apps.
For years now I’ve noticed that sharing photos from Close-up to particular share extensions would trigger a crash. This isn’t uncommon when using the share sheet since extensions are heavily memory constrained. I’ve always kind of just blamed it on the OS memory limit or those share extensions and ignored the issue.
A few weeks ago I decided to see if I could work around this.
I started off by assuming the issue was related to the image being shown onscreen in these extensions. I went down the rabbit hole of implementing some more niche APIs that UIActivityItemSource
provides assuming the thumbnailing would cause those extensions to stop running out of memory. Alas, at the end of this there was no difference, those extensions still crashed. Bummer.
After this it occurred to me that, despite videos and GIFs being much larger than images, the third party share extensions in question had no issues when receiving those data types.
The main difference between how Close-up shares photos and videos/GIFs is that photos are shared as UIImage
objects whereas videos and GIFs are shared as NSData
. I tried sharing images as NSData
instead of UIImages
and Eureka! No more crashes!
Turns out this is all it took:
This is highly speculative, but what I think is happening here is that when certain extensions receive UIImage
s they convert them to NSData
and keep that data in memory to upload. Because of this, that data counts towards the extension’s very low memory limit. By passing NSData
to the extension instead the data counts towards my app instead of the extension. The improved performance could also be related to memory mapping, since the data I’m passing is from files on disk.
A few days later I was talking to my friend Dave about his app Delayte. He mentioned that he was doing a bunch of work to downscale images when sharing to Messenger because it would always crash. This sounded familiar, so I told him about my discovery of passing image data instead of image objects. Later that night he gave it a try, and it seems to work for his product as well!
So, tl;dr — pass images as NSData
instead of UIImage
s to UIActivityViewController
to reduce share extensions crashing.