Delaying deserialization with Mantle until it's needed
I’m using Github’s Mantle in a small side project where I recently started running into performance bottlenecks with it. I have JSON that looks roughly like this:
A bunch of Things, which each has an array of Widgets. I’ve been working with a fairly large data set recently: 70ish things, and a grand total of 1,341 widgets across all of the things at the moment. On older devices (iPhone 4, iPad 2) deserializing all of that at once was unreasonably slow: I could easily see 5-10 second times for it.
Profiling showed that most of the time was spent in Mantle. I really didn’t want to have to drop it: i’s straightforward to write the deserialization code myself, but there are a lot of types that I’d need to do it for, and this particular project I only get to spend a few hours a week on.
Fortunately, I came up with a good workaround: I don’t need that widgets array until it’s time to render a Thing, and there’s only ever one Thing on the screen at a time. I can just delay deserializing the Widgets until rendering time.
How do we do that with Mantle?
First, the class interface looks like this:
And in the implementation file, I tell Mantle what class that widgets array is supposed to be:
What I can do instead is remove the +widgetJSONTransformer
method so Mantle no longer knows
how to deserialize that field: that results in Mantle just setting widgets
to the raw NSArray
of NSDictionaries that it was handed in the first place. Then, add a new readonly field that
deserializes those widgets on demand.
In the header file:
And in the implementation:
With that, we’re good to go: I just replace references to -widgets
with -parsedWidgets
in the rendering code.
Due to when I’m calling -parsedWidgets
the deserializing ends up happening on
the main thread, so I might need to get a bit fancier in the future. For now things are
sped up dramatically without having to write a bunch of accessor code, so I’m happy.