Ole Begemann: iOS Development

iOS SDK, Cocoa and Objective-C

iOS development highlights: August 2010

without comments

Here are some of the things from across the iOS blogosphere I found interesting this past month. I hope to return from my summer blogging hiatus soon.

Written by Ole Begemann

August 31st, 2010 at 11:05 pm

Posted in Uncategorized

iOS development highlights: July 2010

without comments

Unlike myself, the iOS developer community has been quite active posting great content this month. Here are some of the things I found most interesting from across the blogosphere:

Written by Ole Begemann

July 31st, 2010 at 10:41 pm

Posted in Uncategorized

WWDC 2010 videos already available. And free!

without comments

Apple has already posted the videos recorded at WWDC last week. And what’s even more incredible: they are downloadable for free at http://developer.apple.com/videos/wwdc/2010/ for registered Apple developers! Last year’s videos were only free for WWDC attendees and were priced $299 (iPhone sessions only) or $499 (iPhone and Mac sessions) for the rest of us. And even at that price they were worth it. If you are serious about iOS development, do yourself a favor and watch as much of these 100 hours of material as possible. You are guaranteed to learn a lot.

WWDC 2010 Videos available screenshot

PS: Keep in mind that the contents of the videos are still confidential, just as they were for WWDC attendees. Apple will not be amused if we share any non-public information we learn from the sessions.

Written by Ole Begemann

June 18th, 2010 at 12:33 am

Posted in Uncategorized

App Store-safe Page Curl animations

with 16 comments

Even if its usefulness is questionable, the page curl has become one of the signature effects of Apple’s iOS devices so it is no surprise that many developers would like to implement this effect in their apps.

iBooks screenshot during page curl

iBooks on the iPad doing a page curl

Apple uses private APIs

The problem is that the page curl animation used by Apple is not exposed in a public and documented API. Steven Troughton-Smith did a great job at documenting how Apple’s implementation works in his post Apple’s iBooks Dynamic Page Curl. Although Steven’s sample code is a bit rough (as Steven himself admits), the inner workings become clear: Apple has written a custom Core Image filter that is accessible with the undocumented kCAFilterPageCurl constant. (Yeah I know, Apple actually tells us in the documentation that “Core Image is not available in iPhone OS”. They lied.)

This filter accepts to input values, inputAngle and inputTime, to control the angle from which the layer is curled up and the magnitude of the curl. For a page curl animation, we would animate inputTime from 0.0f to 1.0f. To attach the filter to a layer, simply add it to an array and assign the array to the layer’s filters property (ignoring that the documentation says this leads to undefined behavior. In this case, undefined behavior is exactly what we want.).

From Steven’s code (edited for clarity):

@class CAFilter;
extern NSString *kCAFilterPageCurl; // From QuartzCore.framework
 
static CAFilter *filter = nil;
 
...
 
// In -touchesMoved:
filter = [[CAFilter filterWithType:kCAFilterPageCurl] retain];
[filter setDefaults];
[filter setValue:[NSNumber numberWithFloat:((NSUInteger)fingerDelta)/100.0] forKey:@"inputTime"];
 
CGFloat _angleRad = angleBetweenCGPoints(currentPos, lastPos);
[filter setValue:[NSNumber numberWithFloat:_angleRad] forKey:@"inputAngle"];
pageView.layer.filters = [NSArray arrayWithObject:filter];

The App Store-safe way

I hope Apple makes this public in the future (and if you want to have it, too, you should file a bug and request it). In the meantime, Tom Brow has written Leaves, a simple component that achieves a page curl effect through a very smart combination of mirrored and shaded layers (for translucent pages) and gradient layers (for shadows). Basically, Tom adds to the layer that contains the page content (topPage):

  1. an overlay to shade the page during the curl animation (topPageOverlay),
  2. a gradient layer that acts as the top page’s shadow during the curl (topPageShadow),
  3. a mirrored image of the page that will be displayed on the back of the topPage layer during the curl (topPageReverseImage),
  4. a nearly-white overlay to soften the topPageReverseImage,
  5. and the page below the current page that will become the new topPage after the curl has finished.

The end result is not quite as stunning as Apple’s solution but it is a very good workaround.

As I played around with Tom’s code (I encourage you to take a look at it, it is very clean), I noticed that LeavesView did not support displaying two pages side by side in landscape mode, so I modified Tom’s code accordingly. At first, I planned to duplicate the entire layer hierarchy for the second page, but then I noticed that even in the side-by-side view it is enough if only the page on the right is animated. It was enough to add a leftPage layer, modify the page skipping algorithm (skip two pages instead of one) and the display of the topPageReverseImage layer (display an image of the next page instead a mirrored image of the current page). This is what you get:

Leaves project page curl screenshot

Page curl in the Leaves project in side-by-side view

The code is not yet perfect: the topPageShadow is not aligned correctly and I struggled a bit with Tom’s implementation of the page image cache so the code in that section is quite rough. Tom has not yet integrated my modifications into his repository but you can already check out my twopages branch (I love GitHub!). When there is time, I hope we can improve it even more.

Update June 21, 2010: John from maniacdev.com made a nice screencast of the effect in action. Thanks!

Written by Ole Begemann

June 17th, 2010 at 8:20 pm

Posted in Uncategorized

UIWebView’s weird PDF display bug on the iPad

with 10 comments

UIWebView seems to have a weird display bug connected to PDFs and interface rotation in iPhone SDK 3.2. This is how a PDF displayed in a UIWebView looks on the iPad after you rotate the device from portrait to landscape:

UIWebView PDF display bug on the iPad

UIWebView PDF display bug on the iPad (iPhone SDK 3.2)

The PDF appears to be split in half vertically along an edge that was right in the middle of the page while the device was in portrait orientation. The right half is vertically offset from the left half. Other people have also noticed it so I believe it is a genuine bug.

To reproduce it, try the following:

  1. Create a UIWebView and set scalesPageToFit = YES.
  2. Embed the web view in a view controller that supports both portrait and landscape orientation.
  3. Load a PDF file into the web view.
  4. Rotate the iPad from portrait to landscape or vice versa.

Or download the sample project I have created.

I can reproduce this consistently with a number of different PDF files using iPhone SDK 3.2 both in the iPad Simulator and on an actual iPad. The bug does not appear with HTML content nor is it present on the iPhone. It also disappears if you zoom into the page just a little bit or if you set scalesPageToFit = NO.

Workaround: Reload the document after rotation

The only workaround I have found so far is to reload the document after the device has been rotated. It is not very pretty because reloading can take some time and the user can still see the buggy display for a second, but other than that it works. The best place for the reloading code seems to be your view controller’s -didRotateFromInterfaceOrientation: method.

Reported to Apple as Radar #8065859.

Update June 12, 2010: Apple has confirmed this bug as a duplicate to #7790957.

Written by Ole Begemann

June 7th, 2010 at 10:00 am

Posted in Uncategorized

World Cup 2010 Tracker Spreadsheet

with 7 comments

Update June 25, 2010: Now that the group stage is over I have updated the spreadsheet with the results of all the group stage games. If you download it now, you can dive right into the knockout stage.

Update June 7, 2010: There is a bug in the first version of the spreadsheet that results in a wrong team being selected for the seventh game in the Round of 16. Thanks to @galdo for pointing it out. The download link below points to a fixed version.

I haven’t had the need to use a spreadsheet since I quit my job a few years ago, but after getting the iPad I wanted to try out Numbers and so I built a spreadsheet for tracking the 2010 World Cup yesterday. Inspired by Fraser Speirs, who published his World Cup Tracker Spreadsheet last week. Since Fraser’s version requires a little bit of manual effort (it doesn’t automatically determine the winners of the group stage), I thought I could do better and make it fully automatic. I hope you like it:

Download: World Cup 2010 Spreadsheet for Numbers (1.4 MB)

World Cup 2010 Spreadsheet Screenshot 1 World Cup 2010 Spreadsheet Screenshot 2

All you need to do is enter the scores for each on the fixtures sheets (one sheet per group) and, later, on the Knockout Stage sheet. The trickiest part of automating the calculation of the group rankings are the complicated tie-breaking criteria. To rank the teams, the spreadsheet considers the number of points, the goal difference, and the number of goals scored. If two or more teams are still tied on these criteria, the calculation will break. Let’s just hope that won’t happen. (FIFA then considers the match(es) between the teams to break the tie.)

(Beware: I haven’t tested the spreadsheet very thoroughly so there might well be some bugs in the formulas. If you find one, please tell me and I’ll fix it.)

Thoughts on Numbers on the iPad

We already know that the iPad is far more than a consumption-only device and that it has a lot of potential for content creation, as well. That said, it took me a lot longer to build this spreadsheet on the iPad than it would have with Excel or Numbers on a “real” computer. I spent about 4 hours to make this yesterday and I estimate that I could have gotten the same result in about 1 hour with a desktop app. I think the main reasons for this discrepancy are:

  • The iPad’s smaller screen makes it harder to navigate and formatting your content takes more time as you always have to switch back and forth between your content and the inspector.
  • The touch interface is just not as well suited to a spreadsheet app as mouse and keyboard (with powerful keyboard shortcuts) are.
  • As amazing as it is how much functionality Apple managed to put into Numbers on the iPad, it does lack some key functionality (to me), namely multiple selections and the ability to move content between tables without breaking the references (dragging between tables does not work and cutting-and-pasting breaks the references).

Written by Ole Begemann

June 6th, 2010 at 12:18 pm

Posted in Uncategorized

How to debug an app that was launched by Push Notification or URL handler

without comments

I’ve been fairly active on Stack Overflow lately. To date, I have answered 315 questions there and while I haven’t asked any questions myself, I have profited immensely from the knowledge others have shared there. It is truly a great site, so much better than most programming forums. I think many questions that I have answered might also be interesting to you and so I thought I’d share some of the more interesting ones (and the answers, of course) here, perhaps with a little more detail than on SO.

Let’s start with this one: How can I debug an app that was started by an external event such as a push notification or a URL handler? You don’t click on Build and Debug in these cases, so how do we get the debugger to notice? You have two options here:

1. Use NSLog statements and inspect them in Console.app

The output of your NSLog() calls not only show up in the Debugger Console in Xcode but also in the system logs. To look up the logs for the simulator (useful for testing a custom URL scheme), open Console.app in OS X, select Console Messages in the left pane and then search for the name of your app in the Filter field. To see the Console messages on the device (e.g. to test how your app handles an incoming push notification), open the Organizer in Xcode, select your device and switch to the Console app before your app gets launched.

2. Ask the debugger to wait for your app to launch

Sometimes, NSLog() is just not enough and you want the full power of the debugger. No problem:

  1. Set a breakpoint where you want it e.g. in application:didFinishLaunchingWithOptions:.
  2. Select Project > Edit Active Executable. On the Debugging tab, select the “Wait for next launch/push notification” checkbox:
    Xcode Active Executable Settings: Debugging, wait for next launch
  3. Build and Debug as you normally would. The Console will show you a message that the debugger is waiting for your app to launch.
    Xcode: Debugger waiting for app to launch
  4. Launch your app by invoking your custom URL or sending a push notification. The debugger will automatically attach to your app’s process and stop at the breakpoint.

Written by Ole Begemann

May 6th, 2010 at 11:17 pm

Posted in Uncategorized

iPhone SDK Beta to Beta API Diffs

without comments

Apple released a new beta version of the iPhone SDK today. So what changed from the last beta, you ask? It’s a little hard to tell from the links Apple provides on their developer website because the link to the API diffs (iPhone developer account required) always lists all changes from the most recent stable version. So if you have already downloaded beta 1 and beta 2, you are now reading the same document for the third time. Thankfully, Apple also provides a documents that only lists the changes from the last beta version, but it is not listed on the developer home page:

https://developer.apple.com/iphone/prerelease/library/releasenotes/General/iPhoneSeedAPIDiffs/index.html (iPhone developer account required)

This URL seems to remain constant between beta releases. In other words, it always lists the differences between the most recent beta release and its predecessor. If you follow the SDK betas it’s a good idea to bookmark that page.

Written by Ole Begemann

May 4th, 2010 at 10:23 pm

Posted in Uncategorized

Set the zoom level of MKMapView

without comments

A very nice MKMapView category by Troy Brant that allows you to zoom the map by settting the zoom level (as in the Javascript Google Maps API) in addition to Apple’s way of zooming by modifying the map’s region:

Unfortunately, MapKit on the iPhone does not include a way to set the zoom level. Instead, the zoom level is set implicitly by defining the MKCoordinateRegion of the map’s viewport. When initializing the region, you specify the amount of distance the map displays in the horizontal and vertical directions. The zoom level is set implicitly based on these distance values.

Instead of dealing with this region business, I wrote a category that adds support for setting the zoom level of an MKMapView explicitly.

Troy also wrote an extensively detailed post on the mathematical background of his code. Great stuff!

Written by Ole Begemann

May 3rd, 2010 at 6:48 pm

Posted in Uncategorized

I’m available for contract work

without comments

As of now, I am available for contract work developing iPhone and/or iPad apps. If you are looking for an experienced developer who already published an iPad app and a very successful iPhone app (Songtext was the top paid app on the Germany App Store), please e-mail me at ole@oleb.net. I look forward to discussing your projects with you. I am based in Berlin but working remotely or travelling would be no problem.

Ich bin ab sofort auch für Freelance-Aufträge als iPhone- und iPad-Entwickler verfügbar. Wenn Sie einen erfahrenen Entwickler suchen, der bereits eine iPad-App und eine sehr erfolgreiche iPhone-App (Songtext war für einige Zeit die Nr. 1 im deutschen App Store) veröffentlicht hat, kontaktieren Sie mich bitte unter ole@oleb.net. Ich wohne in Berlin, bin aber auch für auswärtige Projekte offen.

Written by Ole Begemann

April 30th, 2010 at 11:43 am

Posted in Uncategorized