Rotating an OpenGL view with touch gestures →

I wrote a tutorial over on Odyssey Computing’s site on using a UIScrollView to back the touch gestures for rotating an OpenGL view. This was something that came up in the context of a larger project that involved incorporating a GLKViewController as a component of a larger UIView-based interface. I love using UIScrollViews to provide pan gesture handling for custom (unconventional) interfaces. In this case I map the contentOffset property of the UIScrollView to the degree of rotation of the GLKViewController‘s model. The great thing about using UIScrollView is that you get deceleration that feels right for free (and where applicable, bouncing).

CocoaConf PDX 2012

I am proud to announce that I will be presenting at CocoaConf PDX in Portland, OR this October.  I’ll be debuting a new talk on something I can’t talk about quite yet.  But it’ll be about something new and fun to play with for you to create great interfaces for your users.

Update: Now that the NDA on iOS 6 has been dropped, I can reveal that my new talk will be on UICollectionViews.

Title: Introducing Collection Views

Abstract: UICollectionView, introduced in the iOS 6 SDK, is Apple’s new class for visualizing data in a grid or really any format other than a vertical list.  We’ll cover the basics and then explore the intricacies of UICollectionViewLayout,  UICollectionViewFlowLayout and related classes.  Along the way we’ll learn how to make both horizontal and vertical grids, cover flow, iPhoto-like stacks, and other custom layouts.  Apple has provided yet another tool that makes it easier and faster for you to provide rich experiences for your users – come learn how to hit the ground running with UICollectionView.  Plenty of source code will accompany the talk.

I’ll also be giving my matrix transformations talk, which now has even more rotational and graphical goodness.  That one is a longer session, so there will be plenty of time to get into all the minutiae of shadows, timing curves, anti-aliasing, rendering layers as bitmaps, etc.  If you’re interested in either FlipBoard-style page-flipping animations or Clear-style folding animations, then you won’t want to miss this session.

Title: Enter The Matrix: Reloaded

Abstract: Matrix transformations can make your user interfaces come to life: translate, scale, and rotate. Each on its own is relatively simple and straightforward. Yet many developers are daunted when 2 or more operations need to be combined. What if you need to rotate or zoom about an off-center (or even off-screen) point? How do you combine multiple transformations into a single animation? How do you make advanced, polished 3D animations such as folding and flipping views? Learn everything you need to know to get started with complex matrix transformations in CoreGraphics and CoreAnimation and take an in-depth look at folding and flipping animations. We’ll also cover related topics such as anti-aliasing, avoiding off-screen render passes, shadows, and rendering retina images. Tons of demos and full open-source source code provided.

I’m super excited to visit Portland and looking forward to Chris Adamson‘s Core Audio Workshop.  There’s even a place where you can get bacon on maple-frosted pastries.

“Bacon maple goodness – so wrong and yet so right”

Early Bird registration ends Sept 14th.

Tips for presenting at technical conferences

I want to present a few tips I have for presenting at technical conferences, specifically at iOS / Mac-focused technical conferences. This isn’t going to be a list of tips on speaking — you can go to Toastmasters for that — just a few things I’ve picked up or think are important.

Have your slides and code posted online by the start of your session

They have to be ready by then anyway, right? Right? So take a few extra minutes to make sure they’re uploaded someplace where they can be shared whether that’s GitHub, DropBox, or your website. There are plenty of free options available, so there are no excuses. How many times have you heard during a session, “I’ll post the slides/code soon” and then how often do you remember to go back and check later to download them?

Bring a few thumb drives with your slides/code on them

Many times conference WiFi is slow, flaky, or nonexistent. Having your materials available online doesn’t necessarily help if your attendees can’t access them immediately. Small capacity flash drives are super cheap nowadays, so buy a few and take a few minutes to copy over your slides and code just before the talk (you know, just after you finish finalizing them).  Attach ribbons or spray-paint them hot pink to help keep track of them.

Bring all your converters, adapters, cables, and chargers

Bring more than you think you’ll need. If the conference projector is VGA, then you’ll definitely want your mini DisplayPort to VGA adapter, but you should also bring your other adapters and maybe an HDMI cable just in case. And if you’re running any iOS apps and have either an iPhone 4S or an iPad 2 or newer, then bring adapters (VGA and/or HDMI) so that you can project directly from the device via AirPlay Mirroring if necessary. (You never know when Xcode might refuse to run your code in the Simulator.) The Apple Digital AV Adapter (HDMI) is especially useful as the only one that lets your do video out from your iOS device simultaneously while debugging or running Instruments from your MacBook over USB, so bring a USB sync cable too.  It goes without saying that you should have chargers for your MacBook and iOS devices as well.

Bonus tip: If you use a retina MacBook Pro or a new 2012 MacBook Air to present, remember to pack a MagSafe to MagSafe 2 converter so that you can charge your laptop using the power adapter that’s hopefully installed on the podium.

Have Contingency Plans

If your session relies on live-coding and/or executing sample code from Xcode, what will happen if Xcode refuses to cooperate with you?  Do you have the code already compiled on an iOS device (possibly multiple) and the cables necessary to present from it?  Do you have git branches or tags for all the major stages of your live-coding demo?  If all else fails, do you have slides showing screenshots of what would have happened?  Expect the unexpected and you will recover more quickly and gracefully when it inevitably happens.

Rev Your Talk

In an ideal world, every conference presentation would be a new original talk crafted specifically for that conference session.  But in reality, good presentations are incredibly time-intensive to create and this just isn’t possible.  I’ve been trying to debut 1 new talk for each conference, but even that may not be sustainable long-term.  Also, some talks are great and should be shared widely with different audiences, so in that sense, repeating them is perfectly acceptable.

However, you should still rev your talk with each presentation:

  • Review your slides and update / correct them as necessary.
  • Fix a bug or add a feature to your sample code.
  • Make a change based on feedback from the previous rendition of your talk.
  • Imagine that someone in your audience attended the previous version of your talk and ask yourself, “What new tidbit of knowledge will I include this time that she didn’t get last time?”
  • And run through your talk at least once, even if you’ve already given it a half dozen times before.

In Closing

Essentially all of the above tips are corollaries derived from the following 2 axioms:

  1. Be Prepared
  2. Respect Your Attendees and Value Their Time

As a presenter you have an obligation to provide value to your attendees.  In exchange for presenting you are receiving entry to the conference, probably accommodation, and possibly airfare and maybe even a speaker’s fee.  But more importantly you will be receiving recognition from your peers and a platform from which to promote yourself, your book, your app, your company, etc.  I know you’re busy with your day job, the next great app, your next book or a demanding high-profile consulting client.  So is everybody else.  You owe it to your audience to put in a modicum of effort (and preferably much more) into each conference appearance.

I encourage you to share your domain-specific knowledge and areas of expertise with the community, and I look forward to seeing you at a tech conference soon.

iOSDevCampDC wrap-up

Last Saturday I had the privilege of speaking at and attending iOSDevCamp DC (which actually took place in Reston, VA).  iOSDevCamp DC is a single day, single track conference that is now in its 4th year.  This was my 2nd year attending.  Unlike most conferences, this one groups all the attendees in a single (large) room for the day (stocked of course with plenty of beverages and snacks as well as breakfast and lunch).  This aspect really helps facilitate the mingling and conversations that make attending conferences so valuable.

I was the 4th of 6 speakers and I gave my matrix transformations talk for the 3rd time in 5 months.  This time I deliberately cut the introductory material somewhat and spent more time on folding and flipping animations plus touched on some general graphics tips like anti-aliasing, rendering retina bitmaps, and avoiding off-screen render passes.  I think it went well.  I forgot to sacrifice to the demo gods beforehand though and got the dreaded bootstrap server error that prevented me from running my demo app in the iOS Simulator.  Fortunately, I had it on my iPad and with the help of the HDMI adapter was able to run Instruments while projecting the iPad screen.

I enjoyed the other 5 talks, but especially Ken Yarmosh‘s talk on gestures and Jonathan Blocksom‘s iOS concurrency talk.  I think I picked up about 3 different nuggets from Jonathan’s talk alone that made attending worthwhile.

Slides from my “Enter The Matrix: Reloaded” talk can be found here (latest version here), and the code can be found on GitHub.

(Presenter tip: If you use a retina MacBook Pro or a new 2012 MacBook Air to present, remember to pack a MagSafe to MagSafe 2 converter so that you can charge your laptop using the power adapter that’s hopefully installed on the podium.)

MPFlipViewController: a page-flipping container controller


I put a project called MPFlipViewController up on GitHub. It’s a page-flipping container view controller that allows the user to flip through a series of view controllers as if they were pages in a book. It is based on the MPFlipTransition class I already have on GitHub, but instead of being just a transition between 2 views, it is a full-fledged container view controller that supports panning and swiping between pages (child view controllers). It follows the Containment API introduced in iOS 5, so it behaves as a proper container view controller similar to the system container controllers (e.g. UINavigationController, UITabBarController and UIPageViewController).

Requirements

Xcode 4.3
iOS 5
ARC

API

The API is based on the API for UIPageViewController (since they fulfill an almost identical role). There is a data source protocol that you implement to specify the previous and next pages, and a delegate protocol that you implement in order to receive feedback on whether or not a page-turn operation completed and also to optionally specify the new orientation in the event that device orientation changes (i.e. user rotates the device).

Use

To create a flip controller use the initWithOrientation: method and pass in the desired orientation (horizontal or vertical):

- (id)initWithOrientation:(MPFlipViewControllerOrientation)orientation;


To set the content use the setViewController:direction:animated:completion: method where direction indicates whether the animation should be a page flip forward or backward.

- (void)setViewController:(UIViewController *)viewController 
                direction:(MPFlipViewControllerDirection)direction 
                 animated:(BOOL)animated 
               completion:(void (^)(BOOL finished))completion;

To enable touch gestures (panning and swiping between pages) implement the MPFlipViewControllerDataSource delegate to provide the previous and next pages (if any). Return nil for either method to indicate the user is already on the first or last page.

- (UIViewController *)flipViewController:
          (MPFlipViewController *)flipViewController
      viewControllerBeforeViewController:
          (UIViewController *)viewController;

- (UIViewController *)flipViewController:
          (MPFlipViewController *)flipViewController
       viewControllerAfterViewController:
          (UIViewController *)viewController;

To be notified of whether a page turn animation completed or not, set the MPFlipViewControllerDelegate and implement the optional flipViewController:didFinishAnimating:previousViewController:transitionCompleted: method. This method is only called if the page turn was gesture-driven (i.e. in response to a pan or swipe), and not programmatic (i.e. in response to a call to setViewController:direction:animated:completion:).

- (void)flipViewController:(MPFlipViewController *)flipViewController 
        didFinishAnimating:(BOOL)finished 
    previousViewController:(UIViewController *)previousViewController 
       transitionCompleted:(BOOL)completed;

To change the orientation of the flip controller when device orientation changes, set the MPFlipViewControllerDelegate and implement the optional flipViewController:orientationForInterfaceOrientation: method and return the desired orientation.

- (MPFlipViewControllerOrientation)flipViewController:
                       (MPFlipViewController *)flipViewController 
                   orientationForInterfaceOrientation:
                       (UIInterfaceOrientation)orientation;

Demo Project

The GitHub project includes a sample project that demonstrates the use of the control and its API.

Don’t rename your .xcdatamodeld file

Ok, you can rename it but be prepared for weird bugs with Xcode 4.3 (and possibly earlier versions).  In my case I created a new Core Data model file and added it to an existing project.  Then I renamed the model file before attempting to build the project.  Yet even with a clean build and install (deleting the app from the device first), NSManagedObjectModel -initWithContentsOfURL returned nil even though my NSURL pointer was non-nil.

NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"ModelName"
    withExtension:@"momd"];
__managedObjectModel = [[NSManagedObjectModel alloc] 
    initWithContentsOfURL:modelURL];

Short answer: quit and reopen Xcode to fix the problem.

(Solution via Stack Overflow)

On the importance of setting contentsScale in CATextLayer

The retina display iPhone has been out for 2 years now, so I probably should have run into this before, but as I use CATextLayer infrequently I had not.  Anyway, if you don’t manually set the contentsScale property of your CATextLayer to the correct value, on retina devices you’ll end up with blocky pixel-doubled text like this:

However, if you call:

if ([layer respondsToSelector:@selector(setContentsScale:)])
    [layer setContentsScale:[[UIScreen mainScreen] scale]];

then you will get properly rendered text like so:
(Solution via StackOverflow.)