One of the examples earlier was loading complicated table data, which is something that can add complexity to an app as the amount of data in the table grows. Delaying until willActivate to load data into the table buys you time, but you still need to load the data at some point. The best and easiest way to make this faster is to simply load fewer rows. Users aren’t going to want to scroll through 10,000 rows on their watches using their finger or the Digital Crown anyway, so capping the total number of rows can go a long way toward making the app responsive. Another technique that can give the appearance of performance is to load part of the data first and then load the rest asynchronously afterward so it’s there when the user scrolls. Let’s implement this method in TapALap to help it remain as fast as possible.
Open up TapALap and head to RunLogInterfaceController.swift. You’ll modify the willActivate method to load five rows at a time:
1: | override func willActivate() { |
- | super.willActivate() |
- | |
- | guard let runs = runs else { return } |
5: | |
- | runTable.setNumberOfRows(max(runs.count, 5), withRowType: "RunRow") |
- | |
- | for i in 0 ..< runTable.numberOfRows { |
- | guard let rowController = runTable.rowControllerAtIndex(i) |
10: | as? RunLogRowController else { continue } |
- | |
- | configureRow(rowController, forRun: runs[i]) |
- | } |
- | |
15: | if runs.count > 5 { |
- | var position = 5 |
- | |
- | let groupsOfFiveRuns = 5.stride(to: runs.count, by: 5).map { |
- | Array(runs[$0..<$0.advancedBy(5, limit: runs.count)]) |
20: | } |
- | |
- | for next5runs in groupsOfFiveRuns { |
- | NSOperationQueue.mainQueue().addOperationWithBlock { |
- | let range = NSMakeRange(position, next5runs.count) |
25: | |
- | self.runTable.insertRowsAtIndexes( |
- | NSIndexSet(indexesInRange: range), |
- | withRowType: "RunRow") |
- | |
30: | for i in position ..< position + next5runs.count { |
- | guard let rowController = self.runTable |
- | .rowControllerAtIndex(i) |
- | as? RunLogRowController else { continue } |
- | |
35: | self.configureRow(rowController, |
- | forRun: next5runs[i - position]) |
- | } |
- | |
- | position += range.length |
40: | } |
- | } |
- | } |
- | } |
This code gets long, let’s break it down. First, at line 6, you use only the first five runs when setting the initial data in the table. Configure those rows as you had before, and then if there are more runs, you iterate through them. Using stride(to:by:), you create a list of integers, which you then map(_:) over to create individual arrays of five runs each. The resulting variable, groupsOfFiveRuns, is an array containing arrays of runs, each with up to five in it.
Once you have these arrays, use NSOperationQueue’s addOperationWithBlock(_:) method on line 23 to delay adding it. These blocks are called on the main queue but after willActivate has already returned, allowing the user to interact with the app while you’re busy adding rows. Inside the block, add new rows to the table on line 26, configure them as usual, and you’re good to go. This small improvement can make a huge difference in the loading speed of your app.
3.145.19.7