How we improved Padgram performance to “incredible” level

Performance is very critical for an app to be successful. One Apple staff ever told me that an app with good performance is a must-have element for it to be featured, even it doesn’t mean one with good performance can be featured.

Performance was a headache for Padgram. We ever received a 1-star rating complaining the performance issue:

We were really upset with the 1-star rating. And we admit that’s a real problem in Padgram V2.2 or lower.

We profiled Padgram from ground, and finally improved its performance to a level that delights users. Like Versuri said:

Here I’d like to write down all my learnings and lessons. This is the first of the series.

(Before start, it worth mentioning that I read several sessions from WWDC regarding performance. And finally I stopped at “Session 318 – iOS Performance in Depth” from WWDC 2011 Session Videos. It highlights all ways to improve performance, while lack of examples. What I am doing here, is more examples, and focus on the ones that actually work for me. )

The first lesson we learnt is: properly adjust workload of UI thread and background thread to avoid UI thread blocked. This is a commonly seen advice. Here I just provide my example.

Instagram API is based on RESTFul API, every API call involves following procedure:

  • Prepare and send the request             <===== in background thread
  • Receive and parse response               <===== ideally, should all be in background thread
  • Update UI                                            <===== in main thread

To better balance the workload, we should only make bold parts above in main thread, and all others in background thread. This is theoretically right but hard to make it right as to the tricky networking library we use.

We use “ASIHTTPRequest” handle network requests. It forces all network completion blocks executed in main thread, regardless of which thread the request is prepared and sent. So in “Receive and parse response” part above, ASIHTTPRequest by default execute completion block in main thread, and we need to use GDC to make CPU intensive work (here in my case, parsing JSON data) executed in background thread.

// Prepare and issue the request in background thread
[httprequest.setCompletionBlock:^{

// the completion block will be executed on main thread
__block NSData *responseData = [httprequest responseData];

// dispatch to decode JSON data in low priority thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{

// CPU intensive work, decode the JSON data
__block NSDictionary* jsonObj = [self decodeData:responseData withEncoding:responseEncoding];

// dispatch decoded data back to main queue for UI update
dispatch_async(dispatch_get_main_queue(), ^{

// update UI
……

});

});

});

In this way, we effectively avoid UI freezing when the app loads data while user interact with the UI. The typical use case is scroll Padgram to the end of a feed (Popular, My Feed, My Likes etc), it starts loading more. We successfully optimized to make the loading not impact user interaction.

To experience how it works, download and try Padgram from App Store.

Further lessons:

  • Choose the right JSON parsing library
  • Kill all offscreen rendering for scrolling animation performance
  • Always set shadowPath for shadowed borders
  • If possible, reduce view blending and hierarchy

I will write them asap.

1 thought on “How we improved Padgram performance to “incredible” level”

Leave a Reply

Your email address will not be published. Required fields are marked *