How we improved Padgram performance to “incredible” level (2)

As planned, I am going to write about “Choose the right JSON parsing library” in this session.

JSON format is popularly used between client and server communication. I’ve not met any open service without JSON interfaces yet. Padgram does a lot of JSON parsing when talking with Instagram server.

Occasionally, I find in a short period, 59% of CPU is used in parsing JSON data. That’s crazy! So I dig into the JSON library we used – SBJson.

The result is pretty obvious, the performance of SBJson is far from good. It ranks only 4th or 5th place compared with major competitors (SBJson is named “json-framework” in the chart):

  

You can read more here: https://github.com/johnezang/JSONKit

Obviously, JSONKit is the best among all competitors. After switching to JSONKit, I’ve never caught the CPU spike like before. (However, I didn’t get round to write testing program myself, I prefer to trust the genius guys in open source community)

In using JSONKit, there are some tips for speed that you should read on https://github.com/johnezang/JSONKit. Among them, we should use NSData over NSString to avoid the overhead to instantiate NSString objects. Here is our decode wrapper function that deals with this:

– (id)decodeData:(NSData *)data withEncoding:(NSStringEncoding)encoding
{

if (data == nil) {
return nil;
}

// this is important for performance, see here: https://github.com/johnezang/JSONKit
if (encoding == NSUTF8StringEncoding) {
return [[JSONDecoder decoder] mutableObjectWithData:data];
} else {
NSString *string = [[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:encoding];
return [string mutableObjectFromJSONString];
}

}

With proper JSON library, and incorporating with proper threading framework, Padgram gets great user interaction experience when scrolling at the same time of loading in the background. You could try Padgram from App Store.

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.

How UI design affects Padgram downloads (stats inside)

A lot of people has suggested UI design (especially app icon) is important for an app. And it’s well proved in Padgram.

In Padgram 1.0, the design uses wooden texture:

Wooden texture is a fashionable design in 2012. It’s said to be good for photo viewing app. Our design combines wooden texture with transparent glass. It has the metaphor that your iPad is a wooden table, you put glass on it and photo over the glass. It’s good, isn’t it? While it’s hard to control from design perspective as it’s used in large scale. Using the app for long time easily causes aesthetic fatigue – it’s the case for our team members, and i bet it also happens on user end.

We realized wood texture might work its best when using only small pieces as decorator or some components like buttons, title bar or tab bar, but if using for the whole background, it’s not easy to control. The most stunning design with wooden texture is from App Design Vault. But after purchased and tried the template, it’s still not suitable for Padgram. And we did the refund (Thanks for App Design Vault to make the refund so easy).

And looking at the icons:

None of them are attractive enough, even for team members ourselves. Then it’s not surprising the download count is not good enough. For the first one month, we average 70 downloads (see below for stats). That’s really shame for a free app!

So we decided to redesign the app. It was painful, we didn’t add features, actually we remove many features. We dropped waterfall view (the reason is written here). We dropped portrait mode support. And we dropped wooden texture, replaced with a simple and light-weighted texture. Below is the new design:

And we hired a designer on Elance to design an icon. It costs us $50, but absolutely worth the money.

Since Padgram 2.0 released, the app downloads are increased for 3.5 times!

The soar was achieved under exactly the same condition: no promotion, no PR. For the reason why downloads are increased so much, the icon counts 70%. And of course the app itself, with unique value, is the key.

As a conclusion:

  • Good design really works
  • Simplify the app, make the core features work the best!
  • App Design Vault can be referred if you want to try some designs. It’s refundable, that’s important!
  • Icon is super important. Make sure you hired the right talent
  • Refer to Elance or Freelancer if you lack of design resource

After receiving many positive feedbacks, we’re confident with what we’re offering. We will start next stage – promotion. I’ll write down what we learned as time goes.

Check out Padgram App Page, or download it here.

Lessons we learnt from EasyPin

EasyPin is the team’s first app. It took 20 days to appear online after submission. It got rejected once by us and once by the App store.  Someone might say it’s not bad, but as a professional app provider, we should never forgive ourselves for any mistakes that we make.We’ve learnt some lessons from the process they are:

  • Don’t risk adding a hacking code for a feature that is rarely used: for a page deeply embedded in the app, we added some hacking code to determine the way a page is opened according to a white list, but the white list can be easily broken as the page could contain some frame and introduce a url out of the white list. The bug is serious. It caused users to be unable to login Pinterest and of course App Store rejected it. The lesson we learnt here is, for a feature that is rarely used, we should not do too much on it unless we have 100% confidence that it doesn’t damage anything.
  • We should set proper rating for the app. Apple replied to us “Since your application allows unfiltered access to the internet, where content with mature or suggestive themes can be accessed, it should be rated 17+. Applications must be rated accordingly for the highest level of content that the user is able to access.”
  • Require “Sneak Peak” if possible. We didn’t raise any pre-buzz before the app is published. This is fine for an app that is only for experiment. But if we have a killer app, we should prepare some buzz before it’s out.

EasyPin is our first app. We admit it’s not a killer app. While we take it seriously and try our best to learn in design, development and marketing. We believe our next app will be the killer app. So stay tuned for our next App.