4. “Speed is money. How much do you want to spend?”
- Old auto racing adage
5. “Speed is developer time. How much do you have left to
spend before release?”
Recall the keynote: "Good cooking takes time. If you are made to wait, it is to
serve you better, and to please you."
6. “Speed is developer time. How much do you have left to
spend before release?”
Recall the keynote: "Good cooking takes time. If you are made to wait, it is to
serve you better, and to please you."
Yup. This is the car my
dad drives. 2009 Ford
Shelby GT-500. He is,
so far, still with us.
7. “death by 1,000 paper cuts”
Displaying Large Amounts of Data Efficiently
13. Derived from this sweet sample code from a WWDC
scrollview session:
http://developer.apple.com/iphone/library/samplecode/
ScrollViewSuite/index.html
18. Drawing UI in a background thread.
Danger, Will Robinson! UIKit is not thread-safe. Try to draw to
screen from another thread, and bad things might happen. Ugly
things are almost guaranteed to happen.You can, however, draw
your images into off-screen buffers (cgContexts work here) and
then grab the pixels that you need to throw on the screen once
the buffer is filled with data. There is nothing stopping you from
filling that data asynchronously and reading it from the main thread
in order to draw it.
19. Drawing UI in a background thread.
1. The first time one of the BigViewPageView objects is asked to
draw, it will create a cgContext into which it will quickly draw a half
opaque white background as a placeholder when the
BigViewPageView is inactive.
20. Drawing UI in a background thread.
II. It will draw whatever is currently in the off-screen context to the
screen in drawRect:
21. Drawing UI in a background thread.
III. It will generate an NSOperation that will fill a new cgContext in a
background thread with the image data as it is needed.
22. Drawing UI in a background thread.
IV. When the NSOperation finishes, it will swap the new buffer in and
call setNeedsDisplay on the view in the main thread so the view
knows to draw the image data to screen. Drawing from a buffer is
fast(er).
23. Drawing UI in a background thread.
V. Any time the BigViewPageView is asked to draw, it pulls the image
data from the current cgContext for drawing; it’s also filling new
cgContexts in the background if you change the expected drawing
size of the image through some bizarre action like zooming. Before
the new buffer is ready, your image will stretch to fill and probably
pixelate for a moment while the NSOperation is preparing new data
much like UIWebView.
24. NSOperation and NSOperationQueue
NSOperationQueue and NSOperation remove much of the pain of
multithreading. NSOperationQueue is a sort of thread pool that
maintains an array of pending NSOperation objects that it schedules
to run in a background thread based on a number of factors from
system hardware to system state to the relative priority of a given
NSOperation.
25. Playing with ^{blocks()}
“Cause it’s gonna be the future soon. And I won't always be this way. When the things that
make me weak and strange get engineered away.”
—Lyrics for The Future Soon by Jonathan Coulton
26. We used to need a patched Compiler
Plugin For Xcode
and a runtime
!
Now we can target iOS 4.0*
29. I’m doing everything the dumb, slow way.
In a background thread.
So the user can still use the app without freezing - up.
30. UIScrollView Zooming
Content
Offset When zooming,
Images Get Stretched
(affine transform)
read: pixellated.
Blech.
ContentView
UIScrollView !
31. As the zoom scale changes, the UIScrollView does two things:
by default
1. It sets an affine transform on the view it is zooming to scale it up or down
without redrawing. It’s a “square” transform that maintains aspect ratio, so there
is no distortion.
2. It resets its own contentSize, contentOffset, and zoomScale so as to hold the
content in place relative to the point about which it is zooming (in the case of
pinching, that point was halfway between your fingers).
We have to do some work to get the pixellated images to redraw at their new
size.
32. Resetting Resolution in a UIScrollView after a Zoom
Operation
Here is how I prefer to do this.
It’s the only way I can get my head around.
33. Resetting Resolution in a UIScrollView after a Zoom
Operation
1. Take a snapshot of the current (scaled)
contentSize and contentOffset.
34. Resetting Resolution in a UIScrollView after a Zoom
Operation
1. Take a snapshot of the current (scaled)
contentSize and contentOffset.
2. Take a snapshot of the current (unscaled)
content view’s frame size; it’s being scaled by an
affine transform, so its actual frame size is the
same as it was before zooming.
35. Resetting Resolution in a UIScrollView after a Zoom
Operation
1. Take a snapshot of the current (scaled)
contentSize and contentOffset.
2. Take a snapshot of the current (unscaled)
content view’s frame size; it’s being scaled by an
affine transform, so its actual frame size is the
same as it was before zooming.
3. Take a snapshot of the current minimum and
maximum zoom scales.
36. Resetting Resolution in a UIScrollView after a Zoom
Operation
2. Take a snapshot of the current (unscaled)
content view’s frame size; it’s being scaled by an
affine transform, so its actual frame size is the
same as it was before zooming.
3. Take a snapshot of the current minimum and
maximum zoom scales.
4. If your scroll view is its own delegate as it is in
BigViewThing, call super to set the minimum and
maximum zoom scales both to 1.0 because setting
zoom on self will eventually call updateResolution
again; infinite recursion is so last year.
37. Resetting Resolution in a UIScrollView after a Zoom
Operation
3. Take a snapshot of the current minimum and
maximum zoom scales.
4. If your scroll view is its own delegate as it is in
BigViewThing, call super to set the minimum and
maximum zoom scales both to 1.0 because setting
zoom on self will eventually call updateResolution
again; infinite recursion is so last year.
5. Set the current zoom scale to 1.0, which will
rescale the content size internally back to the size
of the content view, and reset the affine transform
on the content view to unity.
38. Resetting Resolution in a UIScrollView after a Zoom
Operation
5. Set the current zoom scale to 1.0, which will
rescale the content size internally back to the size
of the content view, and reset the affine transform
on the content view to unity.
6. Calculate new content offset by scaling the stretched/
zoomed offset you took a snapshot of in step 1. You want
the new content to appear in the same place in the scroll
view:
39. Resetting Resolution in a UIScrollView after a Zoom
Operation
6. Calculate new content offset by scaling the stretched/
zoomed offset you took a snapshot of in step 1. You want
the new content to appear in the same place in the scroll
view:
7. newContentOffset.x *= (oldContentSize.width /
contentViewSize.width);
8. newContentOffset.y *= (oldContentSize.height /
contentViewSize.height);
40. Resetting Resolution in a UIScrollView after a Zoom
Operation
7. newContentOffset.x *= (oldContentSize.width /
contentViewSize.width);
8. newContentOffset.y *= (oldContentSize.height /
contentViewSize.height);
9. Divide the old minimum and maximum zoomScale by
the new zoom scale. This scales the original minimum and
maximum zooms relative to the new content size. If
minimum zoom were 1.0 and maximum zoom were 2.0,
when the user zooms to 2.0 and I reset, my new minimum
zoom would be .5, and my new maximum zoom would be
1.0.
41. Resetting Resolution in a UIScrollView after a Zoom
Operation
9. Divide the old minimum and maximum zoomScale by
the new zoom scale. This scales the original minimum and
maximum zooms relative to the new content size. If
minimum zoom were 1.0 and maximum zoom were 2.0,
when the user zooms to 2.0 and I reset, my new minimum
zoom would be .5, and my new maximum zoom would be
1.0.
10. Set the content view’s frame.size to the contentSize
you took a snapshot of in step 1.
42. Resetting Resolution in a UIScrollView after a Zoom
Operation
10. Set the content view’s frame.size to the contentSize
you took a snapshot of in step 1.
11. Set the scroll view’s contentSize to the scaled
contentSize you took a snapshot of in step 1. This stretches
the overall size of the view to match the new zoom level
(but without any affine transform applied).
43. Resetting Resolution in a UIScrollView after a Zoom
Operation
10. Set the content view’s frame.size to the contentSize
you took a snapshot of in step 1.
11. Set the scroll view’s contentSize to the scaled
contentSize you took a snapshot of in step 1. This stretches
the overall size of the view to match the new zoom level
(but without any affine transform applied).
12. Call the setNeedsLayout method on the scroll view.
This will cause layoutSubviews to be called where you can
reset the content view’s internal subview geometry.
46. NSOperation Cancellation
In a category on NSOperationQueue:
- (void)cancelOperationsFilteredByPredicate:(NSPredicate *)predicate;
{
NSArray *ops = [[self operations]
filteredArrayUsingPredicate:predicate];
for (NSOperation *op in ops)
{
if(![op isExecuting] && ![op isFinished] && ![op isCancelled])
{
[op cancel];
}
}
}
We can use this to cancel old, not yet performed, redraws for when the user is zooming in and out rapidly.
48. You can find more information on NSPredicate in Apple’s
Predicate Programming Guide available at http://
developer.apple.com/mac/library/documentation/Cocoa/
Conceptual/Predicates/Articles/pUsing.html.
49. Caching tradeoffs
• Staleness (cached data is old data)
• User interface responsiveness (cached
data is faster data)
• Memory usage (cached data takes up
space somewhere)
50. Different types of iPhone apps
require different strategies
• Where does your data live?
• On-disk read-only
• On-disk read-write
• Client-server read-only
• Client-server read-write
51. Data Request Overhead
• On-disk
• Cloud data
• How much data is optimal per request?
• Parsing and memory overhead (why
NSXMLDocument doesn't exist on the iPhone)
• Limited memory workspace - working in chunks
• How to distribute pauses in UI responsiveness as a
result of requesting data to avoid giving the
appearance of a "slow" application
52. If it might take a while (you did use Shark, right?)...
Stay off the main thread. Please.
54. Look for gogoDocs Google Docs
reader for iPhone and iPad. It’s in an
the app store in your pocket.
(Pay for my flight, please)
jonathan@jonathansaggau.com
http://jonathansaggau.com/blog
twit: @jonmarimba
55. Will Code for food.
jonathan@jonathansaggau.com
http://jonathansaggau.com/blog
twit: @jonmarimba
Nerds for hire // Hiring nerds // Working with Big Nerds