Monday, March 07, 2011

Wednesday, February 09, 2011

Flash Player 10.2 vs. iTunes 10.1.2 CPU Utilization Playing a Song

Flash Player 10.2 was released today. The big claimed improvement is better, i.e. lower, CPU utilization playing H.264 encoded HD video. This tweet claims a big drop in CPU usage for Pandora.com's Flash app.

Curious, I installed Flash Player 10.2 on my main iMac even with the rare Safari pseudo-hang I had on the work laptop after installing Flash Player 10.2

Here's the audio playback performance I see in Mac OS X 10.6.6:

  • Pandora.com playing a song with Flash Player 10.2 uses ~ 10% of CPU
  • iTunes 10.1.2 playing a 256 kbps AAC file ~ 5% of CPU
  • Pandora.com's Flash app paused, ~ 6.6% CPU

Yeah, Flash is totally not going to use more CPU cycles than native Mac OS X audio/video playback Real Soon Now™

Wednesday, February 02, 2011

How To Compare NSDecimalNumbers in Objective-C

I was working on some code today where I had to compare two NSDecimalNumbers. This was my first attempt at comparing them:

NSDecimalNumber *number1 = [NSDecimalNumber one];
NSDecimalNumber *zero = [NSDecimalNumber zero];

if (number1 > zero) {
	//1 is always greater than 0 right?
}

This code will compile without errors or even warnings, but it doesn't work. It works, but it doesn't do what you expect. Turns out you aren't comparing the values of the two NSDecimalNumbers, your comparing pointer addresses.

Even more shocking, Objective-C does not have operator overloading! I've been developing in Objective-C for 3+ years now and I had no idea, it just never came up in iTimeZone. Assuming that Objective-C had operator overloads that did the expected evaluation on the value cost me about 4 hours today, especially since the compiler was no help.

I switched over to this implementation and thought I was done:

NSDecimalNumber *number1 = [NSDecimalNumber one];
NSDecimalNumber *zero = [NSDecimalNumber zero];

if ([number1 floatValue] > [zero floatValue]) {
	//1 is always greater than 0 right?
}

Looks good right? Wrong! While this works for short fractional numbers, numbers that have more precisions will lose them with that syntax. I could have also used:

...
if ([number1 doubleValue] > [zero doubleValue]) {
	//1 is always greater than 0 right?
}

That increases the precision from 6 digits to 15, quite a leap, but some digits could still get cutoff.

The absolutely correct way?

...
if ([number1 compare:zero] ==  NSOrderedDescending) {
	//Hey number1 is greater after all
}

I don't think I am going out on a limb here saying that isn't the easiest to understand syntax. A comment surely would have to go above the if statement to rewrite that in plain english, or even using an operator. While I have only written a few operator overload methods in C++ and none in .NET, I sure did use them in .NET all the time. I hope Objectice-C gets them in a future release.

Saturday, December 18, 2010

How to fix Xcode build error 'Directroy "/XYX/" following -F not found'

I started working on iTimeZone HD, the iPad release, for real today and something pretty weird happened.

I created a new target as a stand alone iPad application based on my current iTimeZone iPhone target. Once I built, first thing I see is this message:

warning: directory '"Macintosh HD/Users/YourName/Code/Project"' following -F not found

This doesn't happen on the iPhone target, and it took me a while to figure out what was going on. Here's what you do to get rid of this annoying message:

  1. Get Info on your Target (e.g. iTimeZone HD)
  2. Click on the Build tab
  3. In the Configuration drop down, select All Configurations
  4. In the search box enter Framework
  5. You should see Framework Search Paths in the results. Click on it.
  6. Press delete
  7. Close the info window and rebuild

You're warning should now be gone.

Saturday, December 04, 2010

Best Way to Implement Private Methods in Objective-C

Since the iPhone SDK came out, I've been using the following syntax in my Objective-C implementation file (the .m) to implement private methods:

@interface ClassName (Private) - (void)privateMethod; @end

@implementation ClassName - (void)privateMethod { //keep this private }
@end

This style just creates a Category for your class that's not in the header, so other classes can't read it. Turns out there was an even better way introduced in the Objective-C 2.0 spec using Extensions, which are like anonymous categories, but the improvement is the implementation must exist in the main implementation block for the class. Here's the example re-written:

@interface ClassName () - (void)privateMethod; @end

@implementation ClassName - (void)privateMethod { //keep this private } @end

Not much has changed, instead of decorating your category with a name, (Private), you just put empty parenthesis, ().

Once I switched over the iTimeZone code base, realized I was carrying some dead weight method declarations, so win!

Here's Apple's documentation.

Update
Check out bbum's comment for additional syntactical sweetness to make private/public properties with property redeclaration.

Thursday, November 11, 2010

Software Development Paradox: The Closer You Are To Zero Bugs The Less You Want To Test

iTimeZone 1.4 reached zero known bugs earlier today and I feel some paralysis. Part of me doesn't want to test anymore because then I will likely find bugs I didn't know about, putting zero known bugs at risk! The other part of me is screaming "Run the fraking test scripts and ship already!"

So yeah, writing this was a stalling tactic, but it made me feel like I was back in control of why I was feeling some paralysis. If nothing else, at least I got to revel in the glory of zero known bugs for a few hours.

Wednesday, November 10, 2010

iTimeZone 1.4 Coming Soon

I've been working on iTimeZone 1.4 iPhone and iPod touch for a long time. iTimeZone 1.3.5 shipped in May 2010, which ended a serious of releases containing incremental bug fix and feature adjustments. I had originally intended to finish an iPad version of iTimeZone for release in early summer, but it got totally derailed. Here's what's coming in iTimeZone 1.4 and what took so long.

iPhone 4 Retina Display Graphics
As iOS developers quickly discovered, the increase over original iPhone - 3GS in required pixels for images means a redo of all assets. I certainly didn't have enough foresight to create all my image assets @2X the needed size, some probably did. iTimeZone 1.4 won't be the last app to get Retina Display images, but in hindsight, should have got the images done and shipped 1.3.6 until holding them until now.

iOS 4 Multitasking
No big deal, it's just a simple recompile right? Yes and no. Yes, you get multitasking enabled in your app for "free" once you recompiled with a 4.x SDK. But you still had to handle those state changes gracefully, for example dumping unnecessary memory caches to be a good citizen. Also, apps that use the Settings app have to handle settings changes once an app is brought out of sleep and made active. Sounds easy, but it took more time to get right than I would have thought because changing the way your app starts exposes all kinds of bugs you never dreamed of.

Better Location Detection
iTimeZone 1.3 added location detection so users could look up cities based on where they were. In my testing before that release, it worked really well. A developers famous last words. Through user feedback post-release and subsequent testing, I realized that the algorithm I used was just not working well enough in large cities. This was a case of App Store reviews being fair, for some it wasn't working and I was getting "1 starred" for it, and rightly so.

I don't know how tough of a problem correlating location data to a database of cities is for other apps or developers, but this has been by far the hardest feature to get to "It Just Works". This feature alone has taken months of development, and caused numerous cascading refactors. The biggest refactor was for the database controller code. I had wanted to clean up this technical debt for other upcoming features, but it burned a lot of time.

There is more testing to be done but in iTimeZone 1.4, location detection is much much better. If more testing confirms, it might even be "It Just Works" good using a combination refinements to the algorithm I used in 1.3 and a reverse geocoding service. This was my first web service call in iOS, so a lot of learning on how to do that right as well. This happens in parallel so as soon as the app gets location info from the device, the user should see results very fast, and should never be left with "Couldn't determine location" unless the device doesn't give it to the app.

This is also the main culprit for iTimeZone for iPad not shipping, I didn't want to ship another big release without fixing this feature.

70,000 More Cities, Fastest Searches Ever
Users always ask for more cities, even the tinniest cities, so I want to give them that. iTimeZone 1.4 is using the biggest city database my existing data provider freely offers. When you increase the size of your data by 4.5X, query performance usually goes down. I saw a decrease in search times putting the new database in 1.3, not even making some of the other changes I wanted to for grouping results.

Grouping the results really slowed things down, and I hate waiting for a device to give me data. Since I was partially refactoring the database controller for the location querying requirements, I just decided to go the whole way to get the maximum parallelism I could using modern OS structures, NSOperationQueue and NSOperation, instead of a query thread with critical section locks in numerous methods. On iPhone 4 and iPhone 3GS with iOS 4.x, a queries first result returns in 1-2 seconds, with lower importance results streaming in a little later.

User Experience Improvements
All of the above are certainly UX improvements, but this part is purely about app flow. In iTimeZone 1.3, when you first opened the app, you immediately got herded into the "Find Current City" screen. If location detection didn't work for you, you had a really bad experience. Now, the app loads into the main screen with some simple directions for the user on what to do. There are a couple other places this happens as well, I think by going just a little slower, the app feels better because users understand the spatial model of the app as soon as the open it. The previous approach could be categorized as "why are you prepared, just go".

The other feature I am constantly asked about is how to change the current city. For a long list of releases, if the user double-tapped any city in their list, it would swap places with the current city. There were also specific buttons in a couple that could be tapped on, but not on the main screen. Problem with a gesture like that, users have to know it's there. So I added a tip on the bottom of the user's city list table telling them how to change the current city. I will definitely be tweaking this again in upcoming releases, maybe implement something on swipe as well, but I hope this makes it more obvious.

Pruning The Source
For the source code to remain healthy, some things had to be removed. Upgrading from the 2.5 year old iTimeZone 1.0 user city storage format was dropped. This slowed every app load down, and highly likely no one left in the world is on iTimeZone 1.0.

iTimeZone 1.4 will only support iOS 3.2 and higher, so long 3.1.3. I posted about SQLite versions in iOS the other day because the SQLite build on iOS 3.1.3 is just not working with one of my queries. Every other device I have & simulator with iOS 4.x works great. Don't think I'm going to revisit this, Apple has moved on, so am I.

What Didn't Make It?
iOS 4 for some reason dropped a lot of time zone abbreviation data iTimeZone was using. I'm going to add my own data set for this, including military time zone names, in iTimeZone for iPad 1.0 and iTimeZone for iPhone 1.4.1

What's Next?
A beta release to private testers in the next couple days, more testing, and then start putting the iPad version back together. I have multiple Subversion merges to look forward to.

Tuesday, November 09, 2010

SQLite Versions Correlated to iOS Versions

As part of developing and testing iTimeZone 1.4 (still in development), I ran into an issue that is only reproducible on iOS 3.1.3. I hadn't been paying attention to the version of SQLite that Apple has been shipping with iOS, but I gathered the info to try and see if that might be the cause of the bug I was seeing. Here it is for posterity:

iOS VersionSQLite Version
3.1.33.6.12
4.0.23.6.22
4.1.03.6.23.2
4.2.03.6.23.2

Wednesday, October 27, 2010

iOS & Mac App Betas Should Be Distributed by the App Store

David Chartier strongly suggested on Twitter that every iOS developer drop what they are doing and sign up for TestFlight, which allows beta testers to download builds of your app over the air.

I had heard of and registered for TestFlight a few weeks ago, but the apps in private beta and I haven't got passed the velvet rope.

After seeing the FaceTime for Mac registration process, it hit me that signing up beta testers should be that easy and handled by Apple. I mean no offense or disruption to the people at TestFlight who sound like they have done amazing work, but this is a job for the App Store itself.

The current Ad Hoc distribution system, which iOS developers use for beta testing, is a huge source of friction. To manage this process, developers have to:

  1. Educate users about what UUIDs are, how to get them, and send them in.
  2. Register a finite number of devices per year on the app store to use for Ad Hoc distribution.
  3. Manage the Ad Hoc provisioning profile to include beta tester devices.
  4. Keep the Ad Hoc profile current on all developer machines.
  5. Distribute the beta build, profile, and instructions on how to get the build into iTunes.
  6. Support strange or busted configurations for testers when things go wrong.
  7. Repeat 1-6 whenever a tester gets a new device or replaces an existing device.

If the App Store handled beta build distribution, here's how it would work:

  1. Tester gives developer their beta tester handle (think like Game Center)
  2. Developer adds that handle to the beta tester tab in iTunes Connect.
  3. Developer uploads beta builds to iTunes Connect.
  4. Tester is notified they've been asked to be a tester for App X. Tester agrees and gets builds through the App Store on device or in iTunes.

This proposal brings the following benefits:

  • Tester devices are managed by the App Store, developers never have to know many there are or when they change.
  • Registering testers for a developers app is a one time process. Of course, either the tester or developer could opt out.
  • Testers get installation and app updates just as they expect with production apps. (Beta's could be badged by the OS).
  • Developers could get crash logs and perhaps console output of their apps through iTunes Connect.
  • Apple could add a crash reporter panel to iOS that only appears to when a beta crashes.

The overall result though would be an increase in quality of apps since more builds would be tested by more people since the process gets so much easier. I hope something like this comes in iOS 5.

Monday, October 11, 2010

Note To Future Time Travelers, Bring Me To The Future!

David Frampton, maker of Chopper and Chopper 2 for iOS, tweeted that we live in crappy times because we're between earth and space exploration periods. I responded saying we don't have a problem because time travelers can just bring us to the future where all the space exploration goodness is.

I want to make it explicit. If somehow you are reading this in the future and we've figured out time travel, please come take me to the future so I can experience time and space travel for myself.

Thanks, Dave

P.S. Trust me, I am totally ready for space and time travel.