Tuesday, December 8, 2009

Every Once in a While...

Since the original release of Beginning iPhone Development about a year ago (has it really only been a year??), there have been several little thing that have happened as a result of the book that have meant a lot to me. Things like seeing the picture of that nine year old kid with an app on the App Store holding up a copy of our book. Things like getting to meet Steve Wozniak. Things like getting tweets from readers thanking us for the book. All sorts of little things that just wouldn't have happened had it not been for the book.

I had another one the other day while I was traveling, and I didn't even really realize it had happened until I got home. On Sunday, I received a tweet that said
FYI: I decided to develop for the iPhone after reading your book, and mainly learned how from it. Thank you! Approved 1st try
Now, that's pretty neat no matter who the author is. Dave and I both love to hear about people who have started programming, or gotten back into programming using our book. It's a huge ego boost for us. It makes us feel good. For me, it makes me feel like I'm paying forward, in a small part, all the help that I've received over the years.

It wasn't until today that I realized that I knew who the author of that tweet is. Dan Bricklin created VisiCalc, the world's first spreadsheet computer program. It was the program that really put the Apple ][ on the map and proved to many people that a "personal" computer could do serious work.

Dan's also a book author, having published Bricklin on Technology this year, and the reviews of it are phenomenal.

If you're curious, check out Dan's first iPhone App: Note Taker.

For those of you who are too young to remember VisiCalc or to have used an Apple ][ outside of a computer museum, this may seems like a minor thing. But for me... well, if I kept a scrapbook, this tweet would go in it, and I would be picking out some really cool stickers to go around it. Glittery stars, dinosaurs. Maybe even dinosaurs with laser guns. And some spaceships. Definitely a couple of spaceships.

Monday, December 7, 2009

Final More iPhone 3 Dev Status Update

I woke up this morning to find all the final, laid out chapters of More iPhone 3 Development in my inbox. Dave and I need to read through each chapter and sign off on them. Once all chapters are signed off, the book is officially done and will be sent to printing.

Dave's already started his review. I won't get a chance to look at them until tonight on the train home from NYC, but we're not more than a few days away from being completely and officially done, which will feel really, really good.

Sunday, December 6, 2009

A Better Two-Finger Rotate Gesture

A while back, I posted a mostly functional, but imperfect sample code for doing a two-finger rotate gesture. I've been meaning to revisit this for some time to get it working correctly.

Tonight, I finally found some time to do so, so I present a better, fully-functional two-finger rotate gesture sample code project. This version allows you to rotate 360° or more without problems. Rather than relying on the order of the touches and the overall rotation angle, I just calculate the angle between the fingers' current location and their previous location.

Screen shot 2009-12-06 at 10.05.04 PM.png
The new version is actually quite a bit simpler than the previous one. Since each instance of UITouch contains both its current location and its previous location, we don't even need to keep track of anything. The old version, in addition to not working correctly past 180° was working much harder than it needed to. The only new thing in this version is that the function that calculates the angle between the two lines looks at the slope of both lines and returns negative or positive values based on which slope is larger.

OpenGL ES Projects and iPhone SDK 3.0

If you're having problems getting any of the older OpenGL ES sample code running under SDK 3.0 - specifically if you get a white screen rather than what you're supposed to see, here is the problem - delete the line of code specified below from the App Delegate's applicationDidFinishLaunching: method:

- (void)applicationDidFinishLaunching:(UIApplication*)application
{
CGRect rect = [[UIScreen mainScreen] bounds];

window = [[UIWindow alloc] initWithFrame:rect]; // <-- Delete this

GLViewController *theController = [[GLViewController alloc] init];
self.controller = theController;
[theController release];

GLView *glView = [[GLView alloc] initWithFrame:rect];
[window addSubview:glView];

glView.controller = controller;
glView.animationInterval = 1.0 / kRenderingFrequency;
[glView startAnimation];
[glView release];

[window makeKeyAndVisible];

}



The problem is that there's already window instance in MainWindow.xib, so creating a new one is problematic - there can only be on instance of UIWindow. Under 2.2.1 and before, it worked, under 3.0, it causes problems. In both cases, the line of code should be deleted, however.

Wednesday, December 2, 2009

Tech Talk World Tour NYC

Well, about 3:30 am this morning, I rolled in from the New York City stop on the iPhone Tech Talk World Tour. It was an exhausting, long, and very, very good day.

Yesterday's tech talk registration opened at 8:00am, with John Geleynse's kick-off presentation starting a little after 9:00. According to John, there were 350 iPhone developers in attendance, and looking around the room, I don't have trouble believing it. There were a lot of iPhone dev geeks sitting in the room. I got to see a lot of old friends, and meet a whole bunch of new people, which is one of the things I love about events like this.

There were three tracks, with five sessions during the day in each, plus a lab that was open all day long. Apple engineers were available for help and for code and UI review.

For me, the highlight of the day was Allan Schaffer's two OpenGL ES talks in the afternoon. They contained a lot of really in-depth technical data that I haven't seen presented before (and I went to all the OpenGL ES talks at WWDC). All of the other sessions I went to had some overlap with sessions I went to at the dub-dub, but they all contained good information and were presented well. I didn't hear a single negative comment from anyone about any of the sessions.

The format and presentation were very much like WWDC except on a much smaller scale, of course. Apple had with them the entire evangelism team, plus people from various engineering teams as well as support staff from Apple Events. We were given a continental breakfast, bagged lunch (but a really good bagged lunch), and we ended the day with a wine and cheese hour, which gave us the opportunity to socialize with each other and with all the Apple employees at the event.

It was a truly great event. I would have gladly paid to attend; the fact that Apple did this for us for free is somewhat mind-boggling to me. I can't imagine what it cost them to put it one. We had a whole floor of the Marriott Marquis, the event was fully catered, and Apple must have brought along somewhere in the range of thirty full-time employees, maybe even more. Plus, we got another Apple T-shirt for our collections, although mine is going into my wife's wardrobe, as it's been quite some time since I could wear size L T-shirt (probably Junior High).

Apple brought great people, presented great information, gave one-on-one consultations to dozens of developers, and they listened. They listened to developer's concerns about a wide variety of issues and gave feedback and insight to help people resolve their issues.

If they do these events again next year and you are an iPhone developer of any ability level, do yourself a favor and sign up as soon as it's announced. Even if you have to travel and spend the night in a hotel, it will be well worth the expense. It's a great opportunity to meet other developers, to talk to people at Apple, and to improve your knowledge of the platform.

So, for anybody at Apple who might stumble across this post: Thank you.

Tuesday, November 24, 2009

Using KVO for Table Updates

If you've followed the guidelines in Apple's Model Object Implementation Guide when creating your data model objects, you can handle your UITableView updates using KVO. This frees you from having to spread calls to reloadData, insertRowsAtIndexPaths:withRowAnimation:, or deleteRowsAtIndexPaths:withRowAnimation: throughout your controller class wherever the data in your table might get changed.

Instead, all you have to do is observe the keypath on your data model object that holds the collection of items being displayed in the table. The easiest way to do that is in your table view controller's viewDidLoad method, like so:

    [self.data addObserver:self
forKeyPath:@"items"
options:0
context:NULL
]
;

Then, you just implement observeValueForKeyPath:ofObject:change:context to insert or remove rows based on changes to the observed collection. The information about which rows were inserted or deleted comes in the changes dictionary stored under the key NSKeyValueChangeIndexesKey. The information comes in the form of index sets, and those have to be converted to index paths in order to update the table. But that's the only thing about this code that isn't fairly straightforward, and this implementation is fairly generic, so you should be able to pretty much copy and paste it into your controller if you want to use it.

If you do do this, make sure you remove all the other remove and insert calls, otherwise you will double-delete and double-insert, which will cause errors at runtime.

- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
NSIndexSet *indices = [change objectForKey:NSKeyValueChangeIndexesKey];
if (indices == nil)
return; // Nothing to do


// Build index paths from index sets
NSUInteger indexCount = [indices count];
NSUInteger buffer[indexCount];
[indices getIndexes:buffer maxCount:indexCount inIndexRange:nil];

NSMutableArray *indexPathArray = [NSMutableArray array];
for (int i = 0; i < indexCount; i++) {
NSUInteger indexPathIndices[2];
indexPathIndices[0] = 0;
indexPathIndices[1] = buffer[i];
NSIndexPath *newPath = [NSIndexPath indexPathWithIndexes:indexPathIndices length:2];
[indexPathArray addObject:newPath];
}


NSNumber *kind = [change objectForKey:NSKeyValueChangeKindKey];
if ([kind integerValue] == NSKeyValueChangeInsertion) // Rows were added
[self.tableView insertRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationFade];
else if ([kind integerValue] == NSKeyValueChangeRemoval) // Rows were removed
[self.tableView deleteRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationFade];

}

Once you've done this, you can forget about reloading your table. Any changes made to the underlying data - even changes made on other threads (assuming your data model class is thread-safe) will automatically trigger an animated deletion or insertion. Although the code above may look a little intimidating, this actually allows a much cleaner overall design.

I've created a fairly simple Xcode project that illustrates using KVO to update a table view.

Friday, November 20, 2009

Private APIs

Fast with the late-breaking news, Gizmodo is reporting that Apple is now scanning submissions for illegal use of private APIs.. Really? Oh, no!

Only, this, um… isn't exactly new. This was already happening, and was already pretty widely known about three weeks ago.