In Folio Case, I'm using a custom UISlider with annotations to allow users to easily skim through the document and find the page they want. When the user taps the knob, a small bubble shows up that shows the page number that corresponds to the position where the knob currently is. The page number within the bubble is constantly updated as the user drags the knob around. When the user lets go, the app turns to the selected page, the knob snaps in place and the bubble slowly fades out. This approach makes sure that the user gets the information when he/she needs it and it doesn't stand in the way of getting things done.
Ever since Folio Case was released, I've been asked how I achieved this effect, as there is no built-in functionality for this behaviour in UIKit. The short answer is: using KVO (key value observing), I track whether the knob is being touched and moved and react appropriately.
The long answer is, well, longer. If you're not familiar with the concept of KVO, you might want to read Apple's Key Value Observing Programming Guide. In short, Apple describes KVO as "a mechanism that allows objects to be notified of changes to specific properties of other objects". In practical use, this means that I can register as an observer to any property other classes expose, such as a UIView's frame. If I choose to do so, I will be notified whenever the object is being moved within its superview, which causes its frame to change.
Now, in order to track a UISlider's knob movement, we will have to get a little tricky. A UISlider instance, once it is being displayed on the screen, has three subviews, all of which are instances of UIImageView. The third and foremost UIImageView instance contains the UISlider's knob. This might change at any time, so if you're going to use an approach like this in production code, be aware that it might change with the next release of iOS. However, the worst thing that can happen in this case is that the bubble won't be shown anymore.
In ARAnnotatedSliderView, which is my class to manage the UISlider and the bubble that is being conditionally displayed, I have the following method:
kARPageScrubberViewKeypathFrame and kARPageScrubberViewKeypathTracking are simple constant NSStrings, @"frame" and @"tracking", respectively. The first property I want to observe is the knob's frame, to be notified of changes in the knob's positioning. The second property I want to observe is the UISlider's tracking property, to be notified when the user starts tracking the knob with his/her finger and when they stop, so I can dismiss the bubble. When one of those notifications kicks in, I react to it using this method:
When the knob's frame was changed, this code makes sure that the bubble view stays right on top of it to ensure a smooth experience for the user. When tracking starts, I can use this notification to display the bubble, and when tracking stops, I can set up a timer to dismiss the bubble after a short while.
As you can see from the complete code, this class is taken from Folio Case without (many) changes, and so is not well configurable. The bubble will always display "Page %d" where a class that was intended as being reusable would probably allow you to customize this setting. I've set up a small example project for this on Github, if you'd like to check it out and play with it. If someone ends up making a fully reusable class out of this, please let me know.
In some of the applications that come with the iPhone, such as the App Store and Mobile Safari, Apple uses a technique for paging-enabled UIScrollViews that show a little bit of the neighbouring pieces of content instead of displaying a single view controller over the whole width of the screen. I think those previews are a really great UI element, since they're much easier to spot than the UIPageControl which usually sits right below the UIScrollView. It shows the user that there is more (or no more) content right next to what they are currently seeing.
If you've ever used UIScrollView's pagingEnabled property, you probably know that this is not easily doable. The UIScrollView will stop only at multiples of its frame's width and cannot be configured to stop at shorter intervals. I recently needed to implement a paging-enabled UIScrollView and was trying to replicate this behaviour and found a way to implement these previews.
One nifty little iPhone feature that left an impression with me is the way that the keyboard in the "Messages" application slides in and out with the keyboard, as if it were attached to it - but it isn't. I needed a similar feature for an app that I'm currently working on for a client, so I decided to investigate how to implement this feature in my own stuff.
Viewing messages, keyboard not shown.
Keyboard displayed. The toolbar moves up, attached to the keyboard.
Although my first instinct was to simply use an implicit animation using UIView's +beginAnimations:context: method, I decided to quickly search the web for some information on how other developers approached this problem.
The results were a little surprising, possibly because the proper way to do it wasn't as easily available before iPhone OS 3.0 - various people on different message boards and mailing lists suggested a hack that involved looping through all instances of UIWindow to find the one containing an instance of UIKeyboard, a private class that isn't even documented in the iPhone SDK. Those hacks then proceeded to modify the dimensions of the view that contains the keyboard and adding the UIToolbar instance as a subview, so it would animate into the key window right along with the keyboard.
Needless to say, these hacks are not exactly future-proof or what I would consider a proper implementation of this feature. The Core Animation route was the one to go, so I proceeded in that direction.
Lately, I have been using a lot of REST APIs for various projects that I have been working on. One development pattern that I have constantly used among all these projects is that of using various NSOperation objects, feed them to an NSOperationQueue and get the results fed back to the caller via delegation.
Why Would You Do This?
Now, why would you go through the trouble of learning all these APIs, creating a delegate protocol and implementing all this stuff if you could use a simple initWithContentsOfURL: (or similar)? The main reason here is asynchronous networking. If you're going to just fetch network data, such as strings, images or whole XML documents from remote servers, you are going to see some latency, especially if you're developing for the iPhone and running on an EDGE or 3G network.
If you were to use synchronous networking from within your main thread, you would be blocking your application's UI until your method stack returns and the system can redraw your views. If you're looking at multiple seconds of latency, which might easily occur if you're fetching dynamically generated data from a server, this practically makes your application unusable. The solution to this problem is to push networking tasks into separate functions and move those to different threads.
Of course, you could just detach new thread selectors all over your controller, but that would be rather ugly, error-prone and a bitch to maintain. Fortunately, Apple introduced NSOperation and NSOperationQueue a while back (in Mac OS X 10.5 Leopard).
For your projects, you will create a subclass of NSOperation and override the -main method to do your bidding. This is where the heavy lifting should take place and all your network latency will not matter anymore. I have written a sample application that uses an NSOperation subclass to fetch an image via HTTP and return it to the controller using a delegate protocol that I have written specifically for this task. My -main method look like this:
This method does nothing more than what you would previously have done to retrieve an image given a URL (_url and _delegate are instance variables that were filled during initialization). The delegate implements the selectors defined in my protocol, errorOccurred: and didReceiveImage:.
So much for the heavy lifting. But how do you actually get this method to run in the first place? This is easy, thanks to NSOperationQueue, which provides a method to queue NSOperation subclasses for execution. In my application controller's -awakeFromNib method, I instantiate my NSOperation subclass and add it to the NSOperationQueue like this:
Add the implementation of the delegate protocol and you're done! What you end up with is a nice, clean and efficient way of dealing with networking that helps to keep your code readable, error-free and makes for a better user experience by keeping the main thread free of blocking operations.