Working With Large Files in an iOS App
How we made Kaleidoscope for iPad as responsive as possible.
Kaleidoscope has been a popular productivity tool for nearly a decade and for good reason: The desktop app makes file comparison and merging seamless, because it’s backed by superior performance.
When we set out to bring Kaleidoscope to the iPad, we knew that the transition would be relatively straightforward. But, because interactions are expected to happen quickly and easily through the tablet’s touch-based UI, we anticipated some hurdles would arise during development. The three biggest challenges were:
- Presenting a large text diff quickly after two text files are compared.
- Responding quickly to UI size changes caused by multitasking (i.e., having a second app open) and device rotations.
- Ensuring that scrolling through a large text diff was smooth and stutter-free.
All of these challenges are related; the common theme is ensuring that the app is as responsive as possible when working with large text diffs.
Weed Out Obstacles
Creating large, complicated text comparisons is time consuming and hinders performance. To make things more efficient, we made sure a text diff is only produced when it’s needed. To help weed out instances where unnecessary text diffs were produced, I made a breakpoint in Xcode that plays a sound and continues execution when a diff is generated. If I ever heard that breakpoint get hit when a diff shouldn’t be generated, I would investigate why.
Use a Concurrent Queue
When building a highly responsive app, it’s important that you perform as much work as possible in parallel. Since a text diff involves comparing two text files, the logic for laying out the diff in the UI also involves doing some things twice (once for each file). We performed those “pairs” of work items at the same time, using an instance of OperationQueue class to create a concurrent work item queue.
For example, calculating the rendered (possibly wrapped) height of each line of text in a file is necessary for various UI layout reasons. Those line-height measurements can take a while to complete, especially for large text files. So I measured the line heights for each file at the same time as separate Operation objects. Those two Operations were added as dependencies of the Operation that used the line height information they collected, so that the work that required the line heights was automatically started once that information became available.
Cache Layout Information
As mentioned above, calculating a text diff’s layout can be time consuming. Once that information exists, it’s kept in memory and keyed by the width of the text diff UI. That cached information helps ensure that rotating the device, or adjusting the window size by having another app open at the same time, will be as responsive as possible. If the user happens to adjust the iPad’s system-wide font size preference, Dynamic Type, that cached layout information is purged, since the font size change requires all layout information to be recalculated.
Using Time Profiler in Instruments can help identify performance bottlenecks. Sometimes a data structure or algorithm that worked great on a small text diff ended up being a serious performance problem with larger data sets. Instruments, specifically the Time Profiler instrument, came in handy to see which of my methods were hogging the CPU. Once the problematic area was identified, a more efficient approach could be devised. The use of Instruments greatly assists in this “get it working then optimize as needed” approach.
Save Time with an Array
Avoid performing many Swift string concatenations, and instead join an array of strings. Using += to build a large string out of many pieces is much slower than adding those smaller strings to an array and then calling the join method. For some large amounts of text, this one optimization reduced the time a method took from 10 seconds to about 10 milliseconds.
New Device, Uncompromising Performance
Performance is arguably even more important on the iPad than it is on the desktop, since users touch the UI and expect an immediate response. Couple that with the fact that iPads have less horsepower than a desktop or laptop computer, and it becomes even more important to stay vigilant about ensuring performance remains as good as reasonably possible.
As we improve Kaleidoscope for the iPad, we will continue to keep performance and responsiveness at the forefront and share our insights with you along the way. Download Kaleidoscope for iPad today and try it out for free for 14 days.