Hacker News new | past | comments | ask | show | jobs | submit login

This app seems to be a blend of native UIKit development and jQuery Mobile. The navigation on the left-hand side is native and really fluid, but on the right-hand side (where the videos and subtitles are) is a UIWebView with jQuery-Mobile-powered pages. That's why the scrolling performance of the subtitles is so shitty (compared to native scrolling) and why the "share" and "download" buttons don't really look native. But an average user wouldn't notice these things, so I guess they're not important.

I just don't understand why the developers didn't do everything natively. What are the advantages of using - in my mind - inferior technology like jQuery Mobile in an app that's completely custom-built anyway? It can't be that much more work to do the whole interface with UIKit.

Other than that I think it's a really good app (and great content, too). So, congratulations to the developers and Sal!




Hi—I'm Adam Ernst, the iOS-side developer of the Khan app.

Your assessment of the app's hybrid nature, and the performance problems that result, is correct. We know that the performance is subpar, and it wouldn't have been much more work for me to do the rest in native code.

Khan Academy recently hired John Resig, with whom I had the pleasure of working on this app. John is the inventor of jQuery and a core developer on jQuery Mobile. He's amazingly talented and has really pushed the Javascript world ahead.

It's no surprise that John is eager to improve jQuery Mobile, and his work at Khan Academy is a great real-world project on which to use it. John tackled the jQuery Mobile side of the project, and I filled in native code for the parts (like the navigation) that would have been far too slow in Javascript.

I'm sure John will continue optimizing jQuery Mobile to improve its performance. So just stay tuned; the jQuery Mobile project has been moving incredibly fast. And thanks, John, for the opportunity to work with you!


> It can't be that much more work to do the whole interface with UIKit.

It really does take that much more time.

Just to use a simple example of displaying a list of data. An experienced web developer can take a list of data from a database or web service, loop through it, and spit out a decent looking page in 10-15 minutes. Maybe take an 15-30 minutes of tweaking and styling to make it really look professional.

Now, doing the same thing on iOS, you use what is called a UITableView. There is no type of magic data binding included, so you have to wire the whole thing up by hand. A bit more extra work but nothing too terrible so far. Now, tableviews are great if you only need to display text in one of 4 predefined ways, but that usually ends up not being the case. You end up having to make your own UITableCells to get things laid out just the way you want. So you make a cell and start loading it up with different label fields, one for each differently styled piece of text you want, image controls, etc etc. Now, if you are doing this the 'right' way, each of these cells should have their own controller because by now the method that is providing the cells to the UITableView has a ton of logic in it and is acting as the controller for your custom cell. But, you have to maintain this list of controllers seperately inside your UITableViewController, further down the rabbit hole you go.

You think you are all done, but depending on how fancy your cells are and how long your list is, you notice the scrolling is jerky, not smooth, not very 'iPhoneish'. So you read some more and figure out the only way to get really smooth scrolling when dealing with complex cells is to manually draw them yourself and not rely on a collection of controls contained inside the cell. So there you sit, drawing out your individual cells with pen-style graphics methods and blitting text and images like you are a video game developer.

Most of the nice interactions you think of as being native, aren't. They are something that a developer had to do by hand. Even something like not having the keyboard cover up a text field has to be done manually.

I'm not saying it isn't worth the time to do a full native app, but it does require a lot of time, UIKit gives you very little for free.


You realize that is just a matter of experience?

Using the frameworks I've developed I can have a iOS app hit a web service and display a list of data in 30 minutes max.

I could write three paragraphs on all the "complex" stuff I'd have to do using JavaScript and CSS and make it sound a lot worst than UIKit just because I am inexperienced.

UIKit gives you so much for free. It is why so many iPhone apps look "iPhoneish" because if you follow the good programming practices you get them for free.


I would be interested in a more specific response to the parent. For example, given your expertise, can you diagnose his problem with jerky scrolling and offer a solution?


Sure, I'll do a deep dive here.

Doing high-performance scrolling is a hard problem. You just can't do it in HTML, at all.

Native code is not a silver bullet. If you're implementing a table view cell, the newbie approach is to just put subviews on the cell for each slice of content. This performs horribly because the graphics card has to composite all the sublayers while you're scrolling.

The faster approach, as he alludes to, is to do everything in one view, using pen operations to move around and blit each section. If you're serious about smooth scrolling, this is what you have to do. Tweetie was famous for its smooth scrolling, for example; it's because Loren Brichter used this approach.

Of course, if you're coming from the web/css world, doing everything with pen operations seems incredibly foreign and backwards. But you get good at it quickly. And it's worth it, UX-wise.


> Doing high-performance scrolling is a hard problem. You just can't do it in HTML, at all.

Not necessarily. Especially with Apple adding momentum scrolling to Mobile Safari in iOS 5. I have no problem smoothly scrolling through tables hundreds of rows long.


Back in the day of the iPhone 3G, iPhone 3GS and to a lesser extent the iPad 1, what adamjernst described below was how you got the best performance http://news.ycombinator.com/item?id=3692126

I would argue that nowadays with the power in the iPhone 4, iPhone 4S, iPad 2 and the new iPad (aka iPad 3) this is a premature optimization. The raw computing power of these devices makes creating a UITableViewCell with basic subviews total useable without affecting scrolling performance. I've worked on almost a dozen iOS apps in the last two years and that is all I do anymore.

Now about diagnosing the problem. 99% of the time the cause of the problem is one of two things:

1) Not reusing UITableViewCells 2) Doing way too much work on the UI thread

UITableView has a method called dequeueReusableCellWithIdentifier: which allows you to get access to a cell in a table view that is no longer being used. This allows you to reuse the cell instead of releasing the memory of that cell and creating a new one.

Memory allocation is expensive and if you had a table with 100 rows you could end up allocating memory for 100 UITableViewCells. Now on the iPhone if you are reusing cells you'd probably only allocate the memory 7-10 times (depending on the height of your rows) and then change little pieces inside it (like the text of the cell or the image that it is displaying). An easy way to see this is to create a demo app that has 1000 rows which are populated with random text, images you include in the bundle. Don't reuse table view cells and scroll up and down as fast as you can. You'll notice the scrolling is choppy. The second you reuse the the table view cells it will "magically" improve.

The second cause is people doing too much work on the UI thread. This is just bad practice and with the advent of Grand Central Dispatch and NSOperation you can simply take a block of code that is eating up a lot of time on the UI thread and pass it into the constructor of a NSBlockOperation and do all the work in the background. Some common examples of this are pulling data from a web service, converting data from a web service into local entities, reading from a local database (i.e. sqlite), sorting collections, etc.

If after solving these two problems your app is still jerky then it is perhaps time to look at adamjernst solution. But in my time I've created some pretty complex UITableViewCells in tables that have hundreds of entries and my scrolling is always butter smooth.


Another way to increase scrolling performance is to only load images after they are visible. However, it is fairly tricky to get it to work.

Doing it in HTML and CSS is indeed a lot easier.


Can you explain how this is tricky to get working?

If we are talking about UITableView then it only asks you for a row when it is about to be displayed. So in that case you are only loading the image when it is about to become visible.

I have no idea how this is done in HTML and CSS but in iOS it is still extremely easy.


It's not bad if all your image assets is locally on device. It become difficult when your assets are remote.

If your image is remote, you'll need to put loading the image on a separate thread, and create a nonblocking http request to fetch the image. The problem is to draw the picture you have to use the main thread, so to make scrolling smoothly become quite a challenge.


So what do you do in HTML and CSS?


This is a very common in iOS. You can preload the array. inside cellForRowAtIndexPath return the array instead of the cell. works perfectly.


I'm not sure what you could mean -- tableView:cellForRowAtIndexPath: returns a UITableViewCell *. Do you have an article describing what you're talking about?


Sorry I wasn't very clear. generally speaking this is a bad idea but it works great if you have a small table.

1) in my ViewDidLoad I create an array of cells.

2) Then in my cellForRowAtIndexPath, I return the particular cell in my array.

- (UITableViewCell )tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

NSUInteger row = [indexPath row];

return [cellArray objectAtIndex:row]; }


But of course, doing pen-style operations instead of declarative markup is precisely what gets you the speed and fluidity of a native app.

When you open a video with many subtitles in the current iPad app, the UI freezes for a couple seconds. Why is that? Well, WebKit is laying out the DOM for a few thousand <li> tags (the subtitles). That takes a lot of time. I'm the iOS developer of the Khan app; I worked with John Resig who did the JS side. Ultimately we decided poor subtitle performance wasn't a big deal.

UIKit could easily add a table class that didn't have such complicated requirements. But then it would be slow, just like WebKit.


Interesting.. Why not have a single element who's text is updated rather than using multiple elements?


I agree with the point of your question, but I do know that in some cases it's a matter of codebase count. Which is to ask would it be better to have 1 codebase that serves as your website and native views? Or is it better to have X number of codebases for your views based on the number of platforms you'd like to be on? Especially when in all cases the views should be the same regardless of platform/native.

Sometimes native is forgone to provide more centralization of views. It's not always good to custom build for every platform when you want consistency in your UX across all platforms.

It all depends.

EDIT: Grammar.


I see where you are coming from. And I agree that it's a trade-off.

But I think my point is, that from a usability point of view you simply have no other choice than having X codebases, one for each platform you want to be on, if you are not willing to compromise on usability. I don't know of anyone who tried themselves at the magical "write once, run anywhere" and delivered a consistently great user experience.

Of course, it would be hyperbolic to say that the Khan Academy app has some huge usability flaws. It hasn't. But I'm mostly thinking about another example here: Facebook. They're a billion dollar web company and even they managed to majorly fuck their mobile apps up in terms of responsibility and general snappiness. They tried "write once, run anywhere" and failed.

There was an article about Facebook's mobile technology on ReadWriteWeb some time ago: http://www.readwriteweb.com/mobile/2011/09/how-facebook-mobi... (I hope this information isn't outdated already) HN discussion is here: http://news.ycombinator.com/item?id=3397872

I think empirical evidence shows that this is the wrong approach if you want to deliver a good user experience.


I'm the iOS developer on the Khan app, and not having to maintain a codebase for multiple platforms is one of the main reasons why we went with jQuery Mobile.

Khan Academy has a lot of custom logic (badges being awarded, points being accrued, and so on) and duplicating that across platforms would be a nightmare.


The app feels much like the WebOS version, so I will guess that they borrowed some of the WebOS code and used it in the iPad version to save time.


Actually, the WebOS version (which wasn't developed in-house) shares no code with the iPad one.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: