Tea Time! 1.1 Update Gets Its Way

bugLast Friday, I decided to fix a bug in Tea Time!. Not so much a bug in Tea Time! actually, but a bug in Apple’s UIPickerView control that showed up when subclassing it. It turns out that it was possible to scroll the picker wheel just so, and one of the rows would come up blank (see screenshot). As far as I could tell, the UIPickerView class was unhappy that I was pre-allocating all the views I was going to show in the picker and handing them out whenever they were requested. So I had to allocate them on the fly or reuse the one in reusingView:

- (UIView *)pickerView:(UIPickerView *)pickerView
        viewForRow:(NSInteger)row forComponent:(NSInteger)component
        reusingView:(UIView *)view;

Once I did that, the bug mysteriously went away. Ah, the joys of dealing with code you have no source to.

So being the tinkerer that I am, I couldn’t just stop there, and I spent an hour fixing something else that was annoying me to no end: When you start Tea Time! there’s always a “click” sound that the picker plays because I’m selecting the last used tea configuration during initialization.

I looked high and low how to fix that, but there seemed to be no way to do it. Nothing in the published SDK information that I could see. But digging through the header file for UIPickerView, I saw this:

@protocol UIPickerViewDataSource, UIPickerViewDelegate;

UIKIT_EXTERN_CLASS @interface UIPickerView : UIView <NSCoding>
{
 //... snip....
  @package
    struct {
        unsigned int needsLayout:1;
        unsigned int delegateRespondsToNumberOfComponentsInPickerView:1;
        unsigned int delegateRespondsToNumberOfRowsInComponent:1;
        unsigned int delegateRespondsToDidSelectRow:1;
        unsigned int delegateRespondsToViewForRow:1;
        unsigned int delegateRespondsToTitleForRow:1;
        unsigned int delegateRespondsToWidthForComponent:1;
        unsigned int delegateRespondsToRowHeightForComponent:1;
        unsigned int showsSelectionBar:1;
        unsigned int allowsMultipleSelection:1;
        unsigned int allowSelectingCells:1;
        unsigned int soundsDisabled:1;
    } _pickerViewFlags;
}

See that last flag? soundsDisabled. Sounds promising, doesn’t it? Unfortunately _pickerViewFlags has @package protection, which means I can’t get to it. Or so the theory goes.

Objective C is surprisingly “good” about letting you get under the hood and bypass protection levels. So I tried accessing those flags with NSObject function setValueForKey, but the stubborn picker would refuse to let me have access and throw an exception instead. Now he was starting to really annoy me. After all, I’m supposed to be working on my other project, not hacking this little app.

I couldn’t stop though. It’s not in my nature.

Oh yeah, Objective C is refusing to give me access to those flags? Fine. I’ll resort to the hackiest or hacks. But I will turn that damn bit off! An object is just a block of memory really, and each member variable is located at a fixed offset from the start of the object. See where this is going? Are you horrified enough? Yup. In the debugger I saw that _pickerViewFlags was exactly 16 bytes from the start UIViewPicker. So I grabbed the pointer to the picker, moved forward to the _pickerViewFlags variable, and stomped the soundsDisabledBit. Mwahahahaha! That will teach you, annoying picker!

Compile, run, and…. “click”. WTF!?!?!? I went in the debugger and checked that I was changing the right bits. Everything was fine. Except that, somehow, the picker was ignoring that. Defeated, I gave up in disgust.

It was that evening when I saw a tweet from @jeff_lamarche about accessing an undocumented function to turn off the sounds in the clicker. Nice timing! He pointed me to his blog post about how to get a listing of all the undocumented SDK functions and how to access them from your programs. I couldn’t believe that there was a function to do exactly what I wanted, but Apple wasn’t exposing it. And for something so simple too!!

It was as simple as

@interface CustomPicker(hidden)
- (void)setSoundsEnabled:(BOOL)isEnabled;
@end

followed by

    [m_picker setSoundsEnabled:NO];
    [m_picker selectRow:settings.m_teaType inComponent:0 animated:NO];
    [m_picker selectRow:settings.m_teaStrength inComponent:1 animated:NO];
    [m_picker selectRow:settings.m_teaFormat inComponent:2 animated:NO];
    [m_picker setSoundsEnabled:YES];

Finally! I had defeated UIPickerView!

Now the catch is, you’re not supposed to use undocumented SDK functions. Apparently that’s grounds for getting your app rejected by Apple and having to resubmit. But I figured I had nothing to lose, and it might be an interesting learning lesson. After all, how exactly does Apple check for undocumented functionality? Do they scan the submitted executable against a set of forbidden entry points? I couldn’t imagine that’s a manual process. But on the other hand, there are reports of other apps getting onto the App Store using undocumented SDK features.

I figured, what the heck, it was a tiny little thing that wasn’t going to hurt anyone. Might as well try it.

teatimeI went ahead submitted the update last Friday, and today (Tuesday) I got the official email with the approval of my new version. Not a bad turnaround time since I imagine they don’t work weekends. It even just made it to the App Store as I was writing this. Shweet!

I’m still left wondering how Apple tries to monitor undocumented SDK usage. Did they not bother with my app since it was so small? Is it really a manual process? (I feel bad for the person in charge of that just thinking about it). Did they catch it and realized it was totally harmless and let it through? Only Apple knows I’m afraid. They really should make their process both more transparent and more consistent and fair for everybody.

But hey, I’m not complaining. No more annoying click at startup 🙂

Twittering Around

twitter_logo_sAs the 0.5% of you who are not using an RSS reader might have noticed, I’ve added a new sidebar with my Twitter activity. I’m pretty new to Twitter… actually, that’s not true. I did join quite a bit ago, but I just didn’t get it. Nobody I knew was really using it and I didn’t want to read a random stream of posts from everybody.

A couple of weeks ago, prompted by seeing a few other indie iPhone devs on Twitter, I decided to give it another try. I’m glad I did! It has been really fun and useful. Unlike Facebook, which is all about connecting with long-lost friends, and seeing pictures people’s new babies, I’m using Twitter exclusively for iPhone development. I keep my follow list to a relatively small amount of people, all of them independent iPhone game developers (so please, don’t feel offended if you’re a friend and I’m not following you).

My routine now consists on sitting to work with a warm cup of tea, firing up the Twitter client du jour, and let it sit in the background (without alerts, thank you). Every so often I check it out, update my status, read what other devs are up to, and get into short conversations. The effect is surprisingly similar to being back working with a team of people and having quick IM conversations with them. Don’t get me wrong, I love working by and for myself, but I do miss the camaraderie, the interactions, and the energy of working with a team of really talented people. Twitter gives me a lot of what I’ve been missing.

Last night, @timhaines put together a Google Spreadsheet of iPhone devs on Twitter, along with a form to add yourself. He sent out a Twitter message asking people to add themselves and pass the word. The effect was stunning. Within minutes there were dozens of devs on the list, and as people continued re-tweeting the message, hundreds more were added! That’s a great resource to hook up with your favorite iPhone developers.

On a similar note, Sam Houston put together a list of video game companies with people on Twitter. That’s not quite as interesting for me right now, but seems like another great resource if you’re into video game development.

So give Twitter a try. Especially if you’re an indie developer working by yourself. Don’t think of it as another Facebook, but as a way to chat and develop connections with other people.

See you there!

Speaking at iPhone Conference And A Teaser

360|iDevI missed the iPhone Tech Talk World Tour last Fall. At the time it wasn’t a big deal because I was still soaking in all the information from the iPhone SDK docs. Now, on the other hand, I’m at the point that I’m getting into more advanced stuff, either not covered in the docs, or that it’s just plain tricky. For example, I spent all day today trying to coerce my app into sending an email with an image attachment–in the end I either kind of succeeded, or I bypassed the problem, depending how you look at it. But that’s another story for another day.

So last week, I was excited to learn there was a new iPhone development conference  called 360|iDev (not the greatest conference name–sounds too much like an Xbox development conference). It looks like a very hands-on, for developers by developers kind of conference, instead of half-marketing, half-development like Apple’s offerings (Yes, we’re already on board, you don’t have to sell us on how cool the iPhone is. We know. We’ve banked our life and savings on it actually). The lineup of speakers looks really promising (including Urban Tycoon author, Mike Huntington).

What really excites me the most is meeting the other attendees though. It looks like it’s not going to be a huge conference (hundreds instead of thousands or tens of thousands like GDC), and we’re all staying at the same hotel, so there should be plenty of opportunities to meet people, chat, trade tips, and compare horror stories over beers.

I actually liked the idea so much, that I decided to jump in and submit a session proposal, and the organizers very kindly accepted it (which is great because otherwise I might not have been able to have afforded going :-)). I’ll be talking about my experience going from a AAA console development environment, to a single-person iPhone development team. Both the obvious differences, the not so obvious similarities, and how a single person can really deliver a top-notch iPhone game.

I encourage everybody to have a look at the 360|iDev site and register if you haven’t already. It’s not very expensive (especially if you buy the ticker sooner, rather than later), and it’s going to be a blast. It’s in San Jose in early March, a couple of weeks before GDC, so no conflicts for game developers there. Also, if you’re interested in speaking, check out their call for speakers while they’re still accepting new submissions. I hope to see some of you there!

On a totally different note, a couple of weeks ago, Evan at Veiled Games (Up There), which is one of my favorite indie iPhone developers, promised to put a daily image with a teaser of their upcoming project. This was soon picked up by Gavin at Antair Games, who is letting us peek under the covers of what’s coming up after Sneezies.

I figured it would be fun to follow their steps, but don’t hold your breath of a daily update. Maybe weekly if you’re lucky. Maybe.

So here’s this week’s teaser. Draw whatever conclusions you want from it 🙂

gnome

Tea Time! Back Up

snappyI was just pleasantly surprised to see that my new sales contract as Snappy Touch for the App Store was approved and that Tea Time! is once again available for sale. I was fearing it would be gone for days, but the blackout only lasted about a day. Not too bad.

The only difference is that now it’s listed with Snappy Touch being the seller instead of my name. Will this be the end of the App Store saga? Let’s hope so.

In the meanwhile, a sales update for those of you curious about it: In the first three days, Tea Time! sold 83 units. On one hand, that’s more than I expect (although I suspect that half of those are people following this blog and my announcement on Facebook). But on the other hand, it’s nothing if you’re trying to make a profit from it, even if it just took a couple of days to put together.

Granted, this is an extreme example. It has gotten exactly zero marketing of any kind, and it’s aimed at a very specific audience. I’m sure if a place like Republic of Tea or Adagio Tea advertised it in their catalogs, sales would go way up. But it gives you a base line of what you can expect in the worst case.

Status: Pending Contract :-(

pending Based on all the horror stories I had read from other developers, I really thought I got out easy submitting Tea Time! It only took a week and a half to approve, there were no complications, and I was able to change to a company status half way through.

I guess I really got out too easy and Apple had to remedy that. Today I found that Tea Time! shows up in the App Store listings, but it’s unavailable when you try to buy it. When I looked in the app management site, much to my surprise, Tea Time! was listed as “Pending Contract”.

What I thought was a relatively fast switch from individual to a company status, just propagated through their database and cancelled my previous contract. So I had to enter all the banking and tax information (exactly the same as before) and wait for the bureaucracy to approve it. So it looks like Tea Time! is going to be out of commission for a few days (or weeks or months?).

It really blows because it will kill whatever little momentum it had. Boy am I glad I went through this now and not with my other project!