Since we had not completely finished up the Core Graphics lab from Day 3,we spent the first hour completing the lab exercise, which was to builda "Tile Game" application where you take an image, split it into tiles,and the user can move the tiles around and try to arrange them in thecorrect way to produce the full image. Actually you don't really splitthe image; you use a grid of custom objects — which are a subclass of
UIControl — and translatethe portion of the image being split to the location in the grid wherethe tile is located. When a user moves the tiles around, each tilestill displays its original portion of the image. So, you are using thesame image but only displaying a portion of the image in each tile.
After completing the lab, Joe went over view transitions. Viewtransitions allow you to easily add common animations (like the peeland flip animations you see on many iPhone apps) to your applicationsto create nice visual effects and a good user experience. For example,in our Tile Game app, when you move a tile it abruptly jumps from theold location to the new location with no transition of any kind. Also,when you touch the "info" button to select a new tiled-image there isno animation. It would be better to make the tiles slide from square to square, and to flipthe tile over to the image selection screen. View transitions let youdo this pretty easily. (Joe mentioned that later we'll be covering CoreAnimation which is more powerful and lets you perform all kinds ofadvanced animations.)
So, to reiterate, view transitions are meant for simple transitionslike flipping, peeling, and so on. There are several "inherentlyanimatable" properties of a
UIView: the view frame, theview bounds, the center of the view, the transform (orientation) of theview, and the alpha (opacity) of the view. For example, to create apulsing effect you could peform two alpha animations one after theother: the first one would transition the view from completely opaqueto completely transparent, and the second animation would transitionback from completely transparent to completely opaque. For the ViewTransition lab we used a "flip" animation to flip between views.
You use class methods of
UIView to begin animations, setup view transitions, and commit the transitions. You use
beginAnimations to begin animations. Then you define the animations using methods like
setAnimationTransition,which set the length of time over which the animation occurs and thetype of animation such as peel or flip, respectively. Then you performactions like add and remove subviews or perform transitions on any ofthe "inherently animatable" properties in an "animation block." Tostart the animations on screen you call
commitAnimationsafter the animation block. This seems similar to how transactions workin a relational database, in that you begin a transaction, define whatyou want done, and then when satisfied you commit those "changes." Joementioned that Core Graphics essentially uses a hidden or offscreenview to store the actions and only shows the animations and actionswhen the animations are committed.
Next up: Core Animation. While view transitions are for simpleanimations, with Core Animation you can animate almost anything youwant. The basic idea here is that when using Core Animation, theanimation takes place on a
CALayer rather than the
UIView. There is one
UIView, and the
CALayer is a cached copy of the content in the
UIView. As soon as an animation begins, the
CALayer are interchanged, and all drawing operations during the animation take place on the
CALayer; in other words when an animation begins the
CALayer becomes visible and handles drawing operations. After the animation ends the
UIView is made visible again and the
CALayer is no longer visible, at which point the
UIView resumes responsibility for drawing.
You create animations using subclasses of
CAAnimation and adding them to the
CABasicAnimationis the most basic form of animation: you can animate a specificproperty, known as a key path, to perform a linear transition from anoriginal value to a final value. For example, using a key path of"opacity" you can transition an object from opaque to translucent, orvice versa.
You can also combine multiple animations using a
CAAnimationGroup, which is itself a subclass of
CAAnimation (hey, that's the Composite design pattern for anyone who cares anymore). You can use
CAKeyframeAnimation to perform nonlinear animations, in which you have one or more "waypoints" during the animation. In other words, with
CAKeyframeAnimationyou define transitions for a specific attribute — such as opacity,position, and size — that have different values at the variouswaypoints. For example, in the Core Animation lab exercise we defined arotation animation to "jiggle" an element in the Tile Game we createdearlier to indicate that a tile cannot be moved. The "jiggle" animationuses the
CAKeyframeAnimation to rotate a tile left, thenright, then left, then right, and finally back to its original positionto give the effect of it jiggling back and forth several times.
To finish up Core Animation, Joe covered how to use Media TimingFunctions to create various effects during animations. For example, weused
CAMediaTimingFunctionEaseIn while sliding tiles inthe Tile Game. Ease-in causes the tile animation to start slowly andspeed up as it approaches the final location. Finally, I should mentionthat, as with most iPhone APIs, you can set up a delegate to respondwhen an animation ends using
animationDidStop. For example, when one animation stops you could start another one and chain several animations together.
After a cheeseburger and fries lunch, we learned how to use theiPhone's camera. The bad news about the camera is that you can't domuch with it: you can take pictures (obviously) and you can choosephotos from the photo library. The good news is that using the camerain code is really simple. You use a
UIImagePickerController, which is a subclass of
UINavigationController, and push it modally onto the top view controller using the
presentModalViewController:animatedmethod. Since it is modal, it takes over the application until the usercancels or finishes the operation. Once a user takes a picture orselects one from the photo library,
UIImagePickerController returns the resulting image to its delegate.
There are two delegate methods you can implement. One is called whenthe user finishes picking an image and the other is called if the usercancelled the operation. The delegate method called when a user selectsa picture returns the chosen image and some "editingInfo" which allowsyou to move and scale the image among other things. The lab exercisefor the camera involved modifying the Tile Game to allow the user totake a photo which then becomes the game's tiled-image.
The accelerometer on the iPhone is cool. It measures the G-forces onthe iPhone. You use a simple, delegate-based API to handleaccelerations. While the API itself is pretty simple, the math involvedand thinking about the orientation of the iPhone and figuring out howto get the information you want is the hard part. But you'd kind ofexpect that transforming acceleration information in 3D space intoinformation your application can use isn't exactly the easiest thing.(Or, maybe it's just that I've been doing web applications too long anddon't know how to do math anymore.)
There is one shared instance of the accelerometer, the
UIAccelerometer object. As you might have guessed, you use a delegate to respond to acceleration events, specifically the
accelerometer:didAccelerate method which provides you the
UIAccelerometer and a
UIAcceleration object. You need to specify an update interval for the accelerometer, which determines how often the
accelerometer:didAccelerate delegate method gets called.
UIAcceleration object contains the measured G-forcealong the x, y, and z axes and a time stamp when the measurements weretaken. One thing Joe mentioned is that you should not assume a baseorientation of the iPhone whenever you receive acceleration events. Forexample, when your application starts you have no idea what theiPhone's orientation is. To do something like determine if the iPhoneis being shaken along the z-axis (which is perpendicular to the screen)you can take an average of the acceleration values over a sample periodand look at the standard deviation; if the value exceeds some thresholdyour application can decide the iPhone is being shaken and you canrespond accordingly. For the lab exercise, we modified the Tile Game touse the accelerometer to slide the tiles around as the user tilts theiPhone and to randomize the tiles if the user shakes the iPhone. Prettycool stuff!
Well, I guess the fun had to end at some point. That point was whenwe covered Web Services, mainly because it reminded me that, no, I'mnot going to be programming the iPhone next week for the project I'mon, and instead I'm going to be doing "enterprisey" and "business"stuff. Oh well, if we must, then we must.
Fortunately, Joe is defining web services as "XML over HTTP" and not as WS-Death-*, though of course if you really want to reduce the fun-factor go ahead Darth. To retrieve web resources you can use
NSURL to create a URL,
NSMutableURLRequest to create a new request, and finally
NSURLConnection to make the connection, send the request, and get the response. You could also use
NSURLConnectionwith a delegate to do asynchronous requests, which might be better toprevent your application's UI from locking up until the requestcompletes or times out.
If you have to deal with an XML response, you can use
NSXMLParser,which is an event-based (SAX) parser. (By default there is notree-based (DOM) parser on the iPhone, but apparently you can use libxml to parse XML documents and get back a doubly-linked list which you can use to traverse the nodes of the document.) You give
NSXMLParser a delegate which recieves callbacks during the parse, for example
parser:didStartElement:namespaceURI:qualifiedName:attributes.Then it's time to kick it old school, handling the SAX events as theycome in, maintaining the stack of elements you've seen, and writinglogic to respond to each type of element you care about. For our WebServices lab we wrote a simple application that connected to random.org,which generates random numbers based on atmospheric noise, and made arequest for 10 random numbers, received the response as XHTML,extracted the numbers, and finally displayed them to the user.
Last up for today was using the iPhone Address Book. There are twoways to use the address book. The first way leverages the standardiPhone Address Book UI. The second uses a lower-level C API in theAddressBook framework.
When you use the Address Book UI, you use the standard iPhoneaddress book interface in your application. It allows the user toselect a person or individual items like an email address or phonenumber. You must have a
UIViewController and define a delegate conforming to
ABPeoplePickerNavigationControllerDelegate protocol. You then present a modal view controller passing it a
ABPeoplePickerNavigationControllerwhich then takes over and displays the standard iPhone address bookapplication. You receive callbacks via delegate methods such as
peoplePickerNavigationController:shouldContinueAfterSelectingPersonto determine what action(s) to take once a person has been chosen. You,as the caller, are responsible for removing the people picker bycalling the
dismissModalViewControllerAnimated method. We created a simple app that uses the Address Book UI during the first part of the lab exercise.
Next we covered the AddressBook framework, which is bare-bones,pedal-to-the-metal, C code and a low-level C API. However, you get"toll-free bridging" of certain objects meaning you can treat them asObjective-C objects, for example certain objects can be cast directlyto an Objective-C
NSString. Another thing to remember is that with the AddresBook framework there is no autorelease pool and you must call
CFReleaseon objects returned by methods that create or copy values. Why wouldyou ever want to use the AddressBook framework over the Address BookUI? Mainly because it provides more functionality and allows you todirectly access and potentially manipulate, via the API, iPhone addressbook data. For the second part of the Address Book lab, we used theAddressBook API to retrieve specific information, such as the mobilephone number, on selected contacts.
Using View Transitions and Core Animation can really spice up yourapps and create really a cool user experience. (Of course you couldprobably also create really bad UIs as well if overused.) The camera ispretty cool, but the most fun today was using the accelerometer torespond to shaking and moving the iPhone. Web services. (Ok, that'senough on the enterprise front.) Last, using the various address bookframeworks can certainly be useful in some types of applications whereyou need to select contacts.
Something in one of the labs we did today was pretty handy, namely that messages to
nil objects are ignoredin Objective-C. There are a lot of times this feature would be hugelyuseful, though I can also see how it might cause debugging certainproblems to be really difficult! There's even a design pattern namedthe Null Object Pattern since in languages like Java you get nasty things like null-pointer exceptions if you try to invoke methods on a
Man, we really covered a lot today, and now I am sad that tomorrowis the last day of iPhone bootcamp. I should become a professional BigNerd Ranch attendee; I think that would be a great job!