Help is needed to translate Padgram into Russian

We always want to do best for our users. Recently we’ve seen big growth in Russia, and we think translating Padgram into Russian could better serve our users. Followed we would also translate it into Thai, Arabic or others.

We’re here calling up volunteers to translate Padgram into Russian. The effort is minimal and several hours should be enough. We need more than one person, so that verification can be done.

As for benefit, we guarantee Padgram will be free forever for the ones that offer help. And we could do shoutout on Instagram for them too. Drop me an email at paul_yan@pinssible.com or simply connect us on Facebook or Twitter.

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.