Thursday, December 23, 2010

Total line count for your Xcode project

The Apple developer ecosystem definitely takes some getting used to when you come from the Microsoft world. Visual Studio is millions of light years ahead of Xcode. That being said, most things are possible with a little work (and bash skills).

I don't claim to have any experience with *nix command line flavors. My command line experience is limited to several versions of MS-DOS back in the day. Luckily, that's where Google comes in handy.

After trying lots of different things, I landed on the following bash command. Open Terminal on your Mac and navigate to your project's root directory. (Handy trick: type cd with a space after it, then drag the root folder into Terminal, and it'll automatically paste in the entire path).
find . -name "*.[hm]" -print0 | xargs -0 wc -l
You'll get a list of every .h and .m file in your project (searching subdirectories recursively), with how many lines are in each file. Finally, you'll get a total line count for all files.

Note that this counts all lines, even blank lines and comments.

Sunday, December 19, 2010

Push notifications in distribution builds

Push notifications may have been sailing along just fine for your app during development. But once you flip the switch to distribution, things may not work as smoothly.

Firstly, I recommend implementing the selector:
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
Throw an alert to tell you what's going on here (you can't NSLog it because you can't attach a debugger to a distribution build -- yet another annoyance).

If you get a message something like: "no valid aps-environment entitlement string found for application," like I did today, you may wonder what that means.

It's a simple solution. Go to and create a new provisioning profile. Make sure the app ID is set to your actual app ID (without any wildcards). Also make sure that your app has Production push notifications enabled properly. The trick is this new provisioning profile. Get it made, download it, and install it in Xcode. Switch your project to sign using this new profile, and you should be golden.

Sunday, December 05, 2010

Learning the value of CATransaction

The iOS API is full of side effects. Although some developers might find these useful, when designing APIs as a product manager, I always insist on limiting side effects as much as possible -- it leads to developer confusion.

One side effect in particular perplexed me to no end this week, and required a lot of crafty Googling to narrow down. I'll post it here in hopes that spreading the information makes it easier to find for others.

The problem
I've got a CALayer, and I'm doing a variety of things including changing it's contents, hidden, and center properties. Changing the contents in particular is what got me -- there was a strange flicker from one image to the next whenever I did it. This made things look terrible, since I'm reusing these CALayers quite a bit in my engine.

The solution
It turns out that CALayer properties all include an implicit animation of 0.25 seconds whenever you set them. When you change the contents property from one image to another, for example, Core Animation actually crossfades between the two images. This is cool, but it really doesn't work for what I'm doing.

You can tell it to stop doing this, luckily, by manually opening a CATransaction before you make your batch of changes, like this:
[CATransaction begin];
[CATransaction setAnimationDuration:0];
When you've finished making changes to the CALayer, commit the transaction like so:
[CATransaction commit];
One gotcha -- if you forget to commit a transaction, the run loop appears to hang (without crashing), causing all sorts of fun problems. Never ever forget to commit your transaction if you open one.

Now let's say you want to nest animations. The outer transaction is set for a 0 second duration, while you want the inner transaction to take 0.5 seconds. Surround the inner transaction with some additional code like this:
[UIView beginAnimations:nil context:NULL];
[CATransaction begin];
[CATransaction setAnimationDuration:0.5];
// Perform animations by changing properties
[CATransaction commit];
[UIView commitAnimations];
Hope it helps!

Saturday, December 04, 2010

touchesShouldCancelInContentView is a life saver!

After a few days of horrible experiences with UIScrollView on iOS, I finally came across the solution from someone at Stack Overflow.

The problem
I have a UIScrollView with a grid of tiles inside it (it's a letter game kind of like Scrabble). When a user places a tile on the board, we want them to be able to pick up the tile again without scrolling the scroll view (and without waiting 150ms). For anyone who's worked with UIScrollView on iOS before, you'll immediately recognize that this is an incredibly difficult thing to do.

The solution
My board controller knows exactly when the user has picked up a piece, and signals it in the isPlaying flag. Armed with this, all I needed to do was put an innocuous little function in my custom UIScrollView subclass:
- (BOOL)touchesShouldCancelInContentView:(UIView *)view
 return !controller.isPlaying;
This tells the scroll view to stop messing around with anything if the user has picked up a piece. Magic!

Thursday, December 02, 2010

Various changes in WoW 4.0.3a and beyond

Finally spent some time in World of Warcraft today. My goal was to grab all the pets I would need to fill out Zee's Logical Pet Usage Flowchart. During my travels, I noticed a few interesting things that Google didn't help me out with.

Flight points
Cataclysm added lots of new flight points to nearly every zone in the old world. So I immediately fired up Google to look for a comprehensive listing of them. And came up dry. Turns out, Blizzard now shows you every flight point directly in-game on the zone maps. The icon looks sort of like a foot with wings. Blue means Alliance only, red means Horde only, and the neutral flight points are sort of... neutral colored.

Hunters need to grab tons of pets to stay competitive in the new WoW. With the expanded 20-slot stable, combined with hunter pets being given nearly every important raid buff and debuff in the game (yes, including Heroism/Bloodlust), today's hunter really needs a comprehensive collection. As of today, a few days before the release of Cataclysm, it's possible to obtain every hunter pet buff in the game except that given by the Shale Spider, a new type of pet found only in Deepholm. The Shale spider gives out the much-needed 5% to all stats buff, otherwise known as Blessing of Kings/Mark of the Wild.

My personal favorite new pet type in Cataclysm is the red fox. These awfully cute creatures happen to belong to the wolf family. I named mine Robin, because he reminds me of the Robin Hood character in Disney's old animated movie. Today I headed out to grab myself a fox, but to my surprise, the Fox Cubs in Redridge are no longer tamable! After a quick trip to Petopia, I hoofed it up to Loch Modan to pick one up (also grabbing the new flight point at Farstrider Lodge while I was there). If you're hankering for the red fox skin, you'll need to do the same.

There's a new rep for both Alliance and Horde this expansion -- worgen and goblin. I popped into Darnassus to grab the new flight point just inside the portal from Rut'theran Village, and happened upon a new pair of quartermasters. The Gilneas Quartermaster was happy to furnish me with a Gilneas Tabard. This tabard gives you Gilneas reputation when you fight in any Classic, WotLK, or Cataclysm dungeons (but not Outland dungeons, by design according to Blizzard).

So I got to thinking -- couldn't I just runecloth my way to exalted with Gilneas? After all, I am tantalizingly close to the new 45 Exalted Reputations achievement -- why wait? But after casting about Darnassus for several minutes looking for the elusive cloth donation guy, I came up empty handed. Turns out runecloth donations are out in Cataclysm, in favor of the new tabard method. Oh, well, you can't get everything for free. Guess they need more stuff to keep us doing the new Heroic Deadmines until we're blue in the face!

That's it for now, but I'm sure there's plenty more to see and do in the shattered World of Warcraft. Until next time!

Wednesday, December 01, 2010

Alpha for CALayer

One of the purposes of this blog is for me to post information that might help other developers, where the info isn't easily found on the web.

Some of these things are silly, and probably obvious to most people. But in today's age of "Google first, ask questions later," it makes sense for me to collect these helpful hints online.

So here's today's tip of the day.

On iOS (and likely OS X -- I don't develop for that platform yet), let's say you've been used to working with UIView-derived objects like UIImageView and UILabel. Let's say you recently decided to change many of your objects to CALayers in order to optimize things a bit.

(I should take a quick time out here to note that in most cases, CALayers won't perform better than UIViews on iOS. But there are advantages, and CALayers are surprisingly easy to work with.)

Anyway, let's say you need to vary the opacity of this CALayer. On your UIView object, the property would be alpha. But on a CALayer object, the property is opacity. That's it. Simple. Profound. And surprisingly difficult to find when you've been programming all day.