iPhone OS 4.0?

January 26th, 2010 by Chris

I know that we are all excited about the mythical Apple tablet materializing tomorrow, but with all the pontification already spread across the far corners of the media, I don’t feel I have much to add to the story. On the other hand, I have been thinking a bit about iPhone OS 4.0. I don’t think we will hear about 4.0 tomorrow if there really is a tablet. It seems like that would just be too much to unload all at once. (I do allow that we might hear about an incremental update such as iPhone OS 3.2 though). Still, we’ll be all out of things to speculate on after tomorrow, so perhaps we can kickstart the next round now?

User Desire

As a user, my hope for iPhone OS 4.0 is a way for third party developers to provide background media playing applications. I understand why Apple wants to be careful with allowing any ol’ process to be granted the ability to run in the background. Sure… power users will be able to manage background processes by hand, no problem. As we have seen on the desktop though, ordinary people just don’t want to be bothered with that level of device tweaking. We have been playing with a few Android devices here at the labs and its clear its pretty easy to start installing apps that quietly add background processes that start to suck down the battery without realizing what you have done.

On the other hand, applications like Pandora on the Android phones are so much better than their iPhone equivalents. Being able to tune in that Pandora radio station and having it play in the background just like the built-in iPod application when you launch another app would change the value of these applications immensely.

My suggestion for how Apple can do this without opening Pandora’s box (zing!) is to create a media service API that allows third party apps to hand media streams off to the iPod player. So the flow would work something like this:

You launch Pandora and use their UI to navigate their music offerings. You tune in the station that suits your current mood and give a bit of a listen. Under the hood Pandora is playing their stream via this new service API that is using the iPod application to serve up the audio. Now, you get the urge to catch-up on your news and launch NetNewsWire for some tasty RSS. When Pandora’s process is terminated the music keeps on playing, because it is the iPod application that is playing the audio. Its all Apple code running in the background, managing how much power is consumed just the way Apple wants, certified to the level of quality Apple is comfortable with, but we get audio from other providers.

There are of course some wrinkles to work out. If I launch the iPod app while a background stream is running, what is ‘Now Playing’? Perhaps the iPod application shows an appropriate image indicating the Pandora app is the current offering and allows you to quickly switch to it. One can even imagine a more sophisticated approach where the Pandora app could provide a plugin bundle that hosts its UI inside the iPod app, though I doubt this is appealing to Apple. There also needs to be some interesting mechanism for the iPod application to ask the originating service for the next or previous media file so that mini-controls that can be used to control the iPod in the background work as expected. Perhaps this is solved through a call-back into a simple code-bundle provided by the third party application? I’ m confident though there is some low impact way to achieve Apple’s goals and still enrich the media-playing experience on the device.

Developer Desire

So that’s my biggest desire as an iPhone user, but what about as an iPhone developer? What I would love to see next is a basic suite of video editing APIs. The problem with the iPhone OS and video right now is that if you want to do anything to process frames of video you need to have your own code to decode the video and re-encode after you have done your processing. This is not exactly trivial code to do well and open source starting points are potentially fraught with licensing and patent peril.

Even if you roll your own codec, perhaps even getting down and dirty with some ARM assembly, you still can’t get access to the built-in hardware assist that allows Apple’s software to capture and encode video at decent performance. The last thing we want to do as an iPhone developer is invest a lot of time in developing a codec for the iPhone and find that the best we can do is H.263 at a miserable frame rate. We also don’t want to force the user to wait around in our application for an encode to finish. Once again we need some way to hand this off and allow the OS to encode in the background for us so our users are not trapped in our application waiting for their edit to finish.

A basic QuickTime derived API that would allow us to take a video file, access individual frames and provide our own sequence of frames to encode into a new movie would be just the ticket. I realize that the advanced encoders typically have licensing requirements and perhaps Apple’s current license for their iPhone software doesn’t allow for this to be opened up. Hopefully it is something that can be addressed in the next version of the OS anyway?

Surely we are in for a interesting ride with the big announcement tomorrow. No doubt the next 6 months will be an interesting one for those of playing with Apple technologies. I suspect WWDC will be chock full of new content this year!

Comments Off

iPhone User Interface Projects

December 17th, 2009 by Chris

Brad and I have recently contributed a chapter to a new iPhone book focused on user interface design and experience from Apress – iPhone User Interface Design Projects.

In our chapter we cover much of the process our team went through to create Postage. Along the way we discuss some of the core concepts and models we employed while designing the user experience. There are also plenty of useful tips, tricks and small details that go into any great iPhone application.

Here is a sample of one of the figures from the book showing some of the early mock-ups of Postage :

Figure 19.png

If you are developing iPhone applications you might want to give the book a browse. Several of the other chapters are very interesting as well. My favorite is Jürgen Siebert’s treatise on fonts. He covers all kinds of great info on type, including a detailed anatomy of letterforms. If you ever wanted to start yourself down the path to claim the title of Font Nerd, his chapter would be a great place to start.

You can grab the book at Amazon or find it on the shelves of any book retailer with a decent selection of software development books.

Comments Off

iPhone Animation Sequence

December 11th, 2009 by Jeff

When writing Postage and WORD SPIN we encountered the same problem again and again: the need to chain a sequence of animations together. For example, when the user navigates to the next page we first animate away the controls for the current view, switch views, then animate the controls in for the new view. Initially, we set the UIView delegate and then in our specified selector implementation kicked off the next animation which itself would eventually call back into a completion selector, and so on. But it’s largely the same code over and over, and you either need a bunch of similar looking animationDidStop implementations, or a single implementation that branches based on the animation identifier. For example:

Old Way


- (void) doMoveFromView1ToView2Animation
{
    [app beginIgnoringInteractionEvents];

    [UIView beginAnimations: @"HideView1Animation" context: foo]; 
    [UIView setAnimationDuration: kDuration]; 
    [UIView setAnimationDelegate: self]; 
    [UIView setAnimationDidStopSelector: 
        @selector(hideView1AnimationDidStop:finished:context:)];

    [self hideView1Code];

    [UIView commitAnimations];
}

- (void)hideView1AnimationDidStop:(NSString*)animationID 
                         finished:(NSNumber*)finished 
                          context:(void*)context
{
    [UIView beginAnimations: @"SwapView1AndView2Animation" context: foo]; 
    [UIView setAnimationDuration: kDuration]; 
    [UIView setAnimationDelegate: self]; 
    [UIView setAnimationDidStopSelector: 
        @selector(swapView1AndView2AnimationDidStop:finished:context:)];

    [self swapView1AndView2Code];

    [UIView commitAnimations];
}

- (void)swapView1AndView2AnimationDidStop:(NSString*)animationID 
                                 finished:(NSNumber*)finished 
                                  context:(void*)context
{
    [UIView beginAnimations: @"ShowView2Animation" context: foo]; 
    [UIView setAnimationDuration: kDuration]; 
    [UIView setAnimationDelegate: self]; 
    [UIView setAnimationDidStopSelector: 
        @selector(showView2AnimationDidStop:finished:context:)];

    [self showView2Code];

    [UIView commitAnimations];
}

- (void)showView2AnimationDidStop:(NSString*)animationID
                         finished:(NSNumber*)finished 
                          context:(void*)context
{
    [app endIgnoringInteractionEvents];
    
    [self doStuff];
}

When we embarked on WORD SPIN it was time to build something to help tackle this problem. I settled on the concept of sequences, where each individual animation is a step in the overall animation sequence. For the user example of moving from one page to the next in Postage, the new code looks like this:

New Way


- (void) doMoveFromView1ToView2Animation
{
    NSMutableArray* steps = [NSMutableArray array];

    [steps addObject: [RSViewAnimationSequenceStep stepWithTarget: self 
                                                         selector: @selector(hideView1Code) 
                                                         duration: kDuration]];
    [steps addObject: [RSViewAnimationSequenceStep stepWithTarget: self 
                                                         selector: @selector(swapView1AndView2Code) 
                                                         duration: kDuration]];
    [steps addObject: [RSViewAnimationSequenceStep stepWithTarget: self 
                                                         selector: @selector(showView2Code) 
                                                         duration: kDuration]];
    
    [[RSSequenceManager sharedManager] invokeSequence: steps];
}

What I really like about this approach is that the entire animation sequence is specified in the same location and it’s clear how many independent steps there are up front, rather than jumping from one place in the code to the next to see what the whole animation will do. Granted, you could almost achieve the same visual effect by refactoring all the “beginAnimation” code into a reusable piece. In fact, that’s how I started.

The fundamental piece of this paradigm is the sequence step. RSViewAnimationSequenceStep inherits from RSSequenceStep, a base class to define the invocation and delegation of the step. RSViewAnimationSequenceStep is primarily a refactoring of the beginAnimation and commitAnimation boiler plate (I’ve removed the definition of the helper, init, and dealloc selectors for brevity):

RSViewAnimationSequenceStep


@interface RSViewAnimationSequenceStep : RSSequenceStep 
{
    id      target_;
    SEL     selector_;
    float   duration_;
}

+ (id) stepWithTarget: (id) target selector: (SEL) selector duration: (float) duration;

- (void) invoke;

@end

@implementation RSViewAnimationSequenceStep

// helper, init, and dealloc removed for brevity

- (void) invoke
{
    [UIView beginAnimations: @"RSViewAnimationSequenceStep" context: nil];
    [UIView setAnimationDuration: duration_];
    [UIView setAnimationDelegate: self];
    [UIView setAnimationDidStopSelector: 
        @selector(animationDidStop:finished:context:)];

    [target_ performSelector: selector_];

    [UIView commitAnimations];
}

- (void) animationDidStop:(NSString *)animationID 
                 finished:(NSNumber *)finished 
                  context:(void *)context 
{
    // delegate is defined in the base class RSSequenceStep (see below)
    [delegate_ stepCompleted: self];
}

@end

The RSSequenceStep is a simple base class to define the general interface:

RSSequenceStep


@interface RSSequenceStep : NSObject 
{
    id  delegate_;
}

@property (nonatomic, assign)   id  delegate;       
    // The object that implements stepCompleted.
        
- (void) invoke;
    // Called to invoke the code necessary for the step. 
    
@end

@interface NSObject (RSSequenceStepDelegate)

- (void) stepCompleted: (RSSequenceStep*) step;

@end

RSViewAnimationSequenceStep encapsulates handling the beginning and ending of an animation, and then calls back to a delegate when complete. It is a self contained item that can be used independently. If so desired, we could stop here and have client code declare the RSViewAnimationSequenceStep, set the delegate to self, and achieve a large part of the refactoring. But the steps would still be spread apart in the code. That’s where the RSSequenceManager, and it’s implementation detail class RSSequence, comes into play, as those two handle chaining the steps together to encapsulate the entire animation.

RSSequenceManager


@implementation RSSequenceManager

// things removed for brevity

- (void) invokeSequence: (NSArray*) steps
{
    RSSequence* sequence = [RSSequence sequenceWithSteps: steps delegate: self];

    [sequences_ addObject: sequence];
    
    if ( [sequences_ count] == 1 )
    {
        [sequence invoke];
    }
}

- (void) sequenceCompleted: (RSSequence*) sequence
{
    [sequences_ removeObject: sequence];
    
    if ( [sequences_ count] > 0 )
    {
        [[sequences_ objectAtIndex: 0] invoke];
    }
}
@end

The bulk of the work, however, happens inside the RSSequence class:

RSSequence


@interface RSSequence : NSObject 
{
    int         currentStepIndex_;
    NSArray*    steps_;
    id          delegate_;
}

- (id) initWithSteps: (NSArray*) steps delegate: (id) delegate;

- (void) invoke;
    // Called to initiate the sequence. 
    
@end

@interface NSObject (RSSequenceDelegate)

- (void) sequenceCompleted: (RSSequence*) sequence;

@end


@implementation RSSequence

- (id) initWithSteps: (NSArray*) steps delegate: (id) delegate;
{
    self = [super init];

    if ( self )
    {
        steps_ = [steps retain];
        
        for ( RSSequenceStep* step in steps_ )
        {
            step.delegate = self;
        }
    }

    return self;
}

- (void) dealloc
{
    [steps_ release];
    [super dealloc];
}

- (void) invoke
{
    [[UIApplication sharedApplication] beginIgnoringInteractionEvents];
    
    currentStepIndex_ = 0;
    
    [self invokeNextStep];
}

- (void) invokeNextStep
{
    if ( currentStepIndex_ < [steps_ count] )
    {
        RSSequenceStep* step = [steps_ objectAtIndex: currentStepIndex_++];
        
        [step invoke];
    }
    else
    {
        [[UIApplication sharedApplication] endIgnoringInteractionEvents];
        
        [delegate_ sequenceCompleted: self];
    }
}

- (void) stepCompleted: (RSSequenceStep*) step
{
    [self invokeNextStep];
}

@end

The sequence manager doesn’t know or care that a sequence is an animation, and a sequence also doesn’t know or care what an individual sequence step does. Those classes only assume that a sequence step’s ending can, but doesn’t have to, come later than its beginning. Given that, we’ve also implemented other sequence step subclasses: one that is a simple selector call, one that encapsulates multiple simultaneous steps, and one that handles openGL animations. I’ve pared the code down a fair bit for this posting, and left out detail — for example, our view animation step handles delays, custom timing functions, and transitions. But the basic idea is all there.

Lastly, Joe Conway over at the Big Nerd Ranch posted a blog about this problem, and described a solution using a subclass of CALayer that calls completion targets for a given animation key. I like his approach because it theoretically handles all the different kinds of animations, and I’ll be thinking about how to work his idea into our sequences.

1 Comment »

Warning : Love hurts…

November 19th, 2009 by Chris

Sometimes the ones you love reject you. If you are an iPhone developer this is probably a concept with which you are already intimately familiar. We love developing for the iPhone, but sometimes the App Store and its app review process leaves us feeling a little dejected.

One of our applications was just rejected about halfway through the review process and it seemed like a unique enough situation that it was worth sharing as a warning to our comrades in the trenches.

Over the past couple of weeks, there have been several reports of iPhone Apps being rejected for use of private APIs. Many of the rejections are from developers that have used the extremely popular Three20 library from ex-iPhone developer Joe Hewitt. The developing consensus is that recently Apple has started using a static code analyzer to flag applications that have used private API calls.

We use a bit of the code from the Three20 library in Postage and caught wind of the issues people had while getting through the review process right before we submitted a new edition of Postage and a couple of related updates. We discovered that even though we didn’t explicitly use the offending code from the library, it was still being linked into our executable because it was in an Objective-C category that added functionality to existing classes. We quickly removed the private API calls from our copy of the library and submitted our new application and updates to Apple.

Nonetheless, we found out earlier this week that our new application was rejected for private API use. The notice from Apple indicated that we had used a private method of UIViewController called previousViewController. Interestingly enough, we did not explicitly use this call anywhere in our code. Looking a bit into the version of the Three20 library we were using revealed that it coincidentally contained a category that added a method to UIViewController called previousViewController.

Once again none of our code or the portions of the Three20 library we used actually exercised this method, but it would appear that the act of compiling and statically linking brings in all the category methods contained in the included headers. I believe that in this case, the category method overrides the built in method, so I’m left with the impression that even if we had been exercising the method in question it would have not been actually using the private API.

While this namespace collision problem is often a topic of debate and pain already among Cocoa developers, those of us developing on the iPhone apparently need to take some extra care now because simply choosing the name of a private API method for your own category method name could result in App Store rejection. Even if you are careful to prefix your own category methods, be sure to take extra caution when incorporating foreign code into your project.

Hopefully this and other possible false positive problems with the new code analysis portion of App Store submissions will be addressed soon. Personally, I’d love to see Apple give us access to the analysis tool to run against our own builds before submission. Or if that’s not possible, perhaps a modification to the review process so this automated analysis happens sooner in the process so we don’t lose so much ground in the now 14-day wait for the review process to complete.

UPDATE :

After looking at a class-dump of the 3.0 frameworks It looks like previousViewController isn’t a private API method, but actually a public method on UINavigationController. This leads me to believe that the email from Apple was incorrect in identifying previousViewController as private. Perhaps the analyzer is tripped-up by a category and a subclass defining the same method? If it is just a bug in the analyzer I guess we can’t really nail down any specific cause of the problem at this time. We made sure there was no trace of any method called previousViewController anywhere in our code, but now I am less certain it will guarantee passing the test next time!

(Thanks to Andrew Wooster)

33 Comments »

TapLynx spotted in the wild

October 14th, 2009 by Chris

Our pal Brent Simmons, noted developer of the renowned NetNewsWire for the for the Mac and iPhone, has just released his latest NewsGator project into the wild : TapLynx.

TapLynx lets you create an iPhone media application without a lick of Objective-C or Cocoa code. Using the SDK you can link against the TapLynx library, configure a plist, edit a few HTML files and in an amazingly short amount of time you’ll have a custom application presenting content from a variety of sources. The framework is adept at displaying, text, image and video content. The user interface is highly configurable and offers a variety hooks to customize the appearance.

I took it for a spin this morning and was able to produce this RogueSheep vanity application that featured content from this blog as well as the @postageapp twitter feed in something like 15 or 20 minutes :

TapLynx - RS Blog.png

Two nifty features :

  • You can add custom tabs running your own code if you have Cocoa expertise.
  • The application configuration can come from a URL, allowing the content and style to update dynamically without submitting a new application instance to the App Store. You can even add new tabs this way!

This is a great addition to any iPhone developer’s toolbox. We are already looking at ways this can help us with several of our clients. Thanks Brent!

5 Comments »

UW Course on Mac and iPhone programming

July 15th, 2009 by Chris

The University of Washington is now offering a certificate course in Macintosh and iPhone programming.

This program is offered in 3 parts, with the first class that introduces objective-C and Cocoa starting this fall. Our good friend Hal Mueller is teaching the first course. The advisory board for this program is comprised of many of the best and well-known Mac and iPhone developers in the region, so you know the content is going to be great.

If you are in the Seattle area and looking to become a master of Cocoa and Objective-C, you don’t want to miss out on this opportunity. I know that the classes will fill up quick, so apply soon.

Comments Off

WWDC 2009!

June 5th, 2009 by Chris

RogueSheep is sending a small contingent of the flock next week to the annual Apple Developer conference, WWDC. Our UI whiz and graphic artist, Brad, will be there and of course I will be representing the business and engineering factions. We plan on giving away a few of our new Postage t-shirts as well as some reprints of our old company shirt from last year with our updated logo. Follow @twenty3 on twitter if you’d like to keep up with where we will be at the conference and to find out how to get a shirt if you are going.

Should be an exciting time for Apple fans with a new MacOS, likely new iPhone hardware and the fresh iPhone OS 3.0. Who knows, maybe even Steve Jobs will descend from the heavens in a divine return to the the helm of the big fruit? I hope to see many of you reading this there.

3 Comments »

Spike Wants You…

April 22nd, 2008 by Chris

for the RogueSheep Army.

Things are really starting to cook around here lately. We have a variety of new clients discussing fresh projects and long-term partners coming back with some exciting plans for the remainder of this year. We are also fully engaged in work on our own technology platform that is centered around automated publishing. It has been a busy year and I think I can still see January back there not too far down the timeline.

Those of you that know me, know that I hate saying no. Having to turn down excellent opportunities and slowing down work on our internal projects one to many times has finally tipped the balance. We are ready to shepherd in a new engineer in the Seattle office in the very near future. The full details and job application form are available online.

Send us your résumé if you are interested or pass the word on to anyone you know that might be a good fit. I’m really looking forward to seeing a few fresh muzzles around here.

Comments Off