Thank you, Mr. Jobs. Thank you, Jobs family, for sharing him with us.
]]>Most of the complaints about the patent system being “broken” come down to a few points:
My Proposal: Within a defined grace period after patent status is granted (I’m envisioning 5 years, maybe 7), the patent holder must show measurable revenue due to a concrete implementation of the patent, or that it is a recognizable part of another product which generates recognizable revenue. This revenue may be recognized directly by the inventor, or by licensees of the patent. If such evidence is not given within the grace period, the patent is considered fallow and control rights are revoked.
A patent that does not result in a concrete implementation within a reasonable period of time is hard to consider as “benefitting society” and thus unworthy of the rights exclusivity granted by the society in exchange.
]]>I just received word that the 2.0 update to ESPN Passport–the last fruits of my contracting with the fine folks of RogueSheep before joining Black Pixel–went live on the App Store today. What started out as “add Facebook Places functionality” became a much smoother, more efficient and focused application that I was proud to have a part in.
If you’re at all interested in adding a social network aspect to your sports watching, go check it out. It’s free, but you’ll need to sign up for a free ESPN Passport login to get the most out of it (Facebook and Twitter logins add even more).
(By the way, have you tried RogueSheep’s latest app, Easy Alarms? I played no part in it, but it rocks all the same.)
]]>During an entertaining aside in Andy Ihnatko‘s keynote at this weekend’s Voices That Matter conference, I was reminded of a thought I’d had a while ago: Why don’t Mac desktop applications store their license info in the Keychain?
Complaining about restoring license keys should be just as trite of a humor topic as little bags of peanuts on flights, but it still holds true. Go to restore a machine, or move to a new one with a clean install, and you can write off at least an afternoon launching and entering at least two text fields per application.
Maybe I’m the only one who feels quite comfortable with syncing to MobileMe–I actually consider it the feature that keeps me coming back. (I do know there are people who have frustrating issues, and I truly feel for them, but I continue to believe they are in the minority.) Given that setup, here’s how I’d see setting up a new laptop:
I’m not expert enough to suggest that it would improve security of your key, but it sure would discourage casual tweaking more than the plist or hidden file schemes you’d need to develop on your own. Also, separation of license key from a preferences file (hopefully developers are already doing this) allows a user to delete the preferences and start fresh without having to worry about relicensing.
I understand that Keychain development can be convoluted, but is that reason enough to not make the user’s life a little bit easier and your support burden of finding a lost license a little less frequent?
As I said at the top, I realize I’m talking out of my…hat here. I don’t have experience doing this (yet), so I am interested in hearing reasoned arguments. Until and unless this is proven untenable, simply consider it a feature request for your next release.
]]>There seem to be some quirks (all videos and podcasts are marked as unplayed on the device) and other behaviors I’d like changed (watching/listening to a podcast on the device doesn’t report that to the shared library). These niggles are really just small issues compared to the big advance of having access to my full library.
Thank you, iOS team!
]]>2010 was one heck of a slingshot year for me and Corporation Unknown. I started the year unemployed and thin on contract work, and finished it with Corporation Unknown’s highest revenue in its 3-year history and a job offer I can’t refuse.
After starting out looking promising, 2009 was rough. The latter half was my first try at full-time independent contracting. I spent time working on project proposals where the client apparently went with someone willing to work for $25/hour; I did work on a decent project (iPhone client for the web site they were developing) that then went “on hold” once the company I was subcontracting for realized that their client was behind on payments to the tune of six digits. (They paid me in full, I don’t know if they ever got the same.)
At the beginning of 2010, my wife and I filed for personal bankruptcy. This isn’t something I’m proud of, but I refuse to hide it as a personal shame. I debated even mentioning this here, except for two points I hope might be able to help others approaching a similar situation:
Independent contracting in 2010 was hot and cold. More accurately, cold then hot, and feast or famine. I’d go without prospects for a while, then have a few come all at once that I actually had to choose from. Managing a client pipeline is not easy as a solo contractor.
In the spring, I had the opportunity to work with local friends Black Pixel on a small part of a fairly large project for iPad–before its release. It’s hard to believe the iPad hasn’t been out a full year yet; recalling having to code for iPad without a test device feels like reminiscing about the punchcard days.
I had a good time working on that project, even though it was all too brief. The team was wonderful, and even though it feels unfair, I have to single out the experience of working with Chris Clark. It was the first time I’d had the opportunity to work on an iOS project with a dedicated designer–one who listens, takes feedback, and respectfully tells you you’re either wrong, or he just prefers his design anyway–and I loved that.
At that time, I was also working on a project with a existing client. They had an iPhone app that I had cleaned up somewhat, and the announcement of iPad seemed an ideal fit for their product. Unfortunately, in the early days of the iPad, I still needed a lot of experimenting to get a feel for what “worked” and what didn’t. In their desire to get in to the field as quick as possible, they felt that the project was taking too long and ended up opting out of the contract.
Then in May, I had the opportunity to do some subcontracting work for fellow locals RogueSheep. The project was for a component of an iPad app that, once I got past the “why would you want to do that?” aspect, provided some interesting challenges in designing custom controls and animations, and I loved that.
RogueSheep is another great team, and another great designer in Brad Ellis (even if he has since moved on to Square). Brad has the same positive qualities as Chris, with the addition of slightly crazier ideas that push you to create something you wouldn’t have imagined on your own.
Thankfully, the Sheep have continued to have a project pipeline for me to work on: I wrote another bit of code that I’m not even sure has made it onto the store yet for the same client; I wrote some UI code for RogueSheep’s own TouchUp for iPad application as they were readying it for release, and I’m in the process of finishing off another pretty major iPhone project for another of their clients. They even let me touch their Apple Design Award.
Thanks in large part to RogueSheep, in its first full year of full-time effort, Corporation Unknown has recorded its highest annual revenue:

This year already has some promising challenges ahead:
2011 is going to be a busy year!
]]>I was going along, minding my own business, implementing a typical -tableView:didSelectRowAtIndexPath: delegate method to create a view controller, push it onto the navigation stack, and then…nothing. The view didn’t appear, and the app interface became unresponsive. Numerous pauses in the debugger showed what would appear to be normal stacks in the running of the app–no infinite recursion going on, thankfully.
The view was actually in a strange nesting of UITableViewControllers, UINavigationControllers and UITabBarControllers, so I reworked that to the bare bones of a UITableViewController pushing a freshly made UITableViewController onto its navigationController. I verified that it was being initialized properly, and that I had a valid navigationController to push onto (and other view controllers did push with the same navigationController). Still no change.
Then I added breakpoints to every UITableViewDelegate and DataSource method I’d implemented, even the trivial hardcoded ones (“return 3;” for -numberOfSectionsInTableView:) at first to ensure they were being called (they were). Thus began the tedium of following the chain of 4 or 5 calls per table row until I found the offending code.
This new table view is composed of a number of sections each composed of only one cell. The cells are designed in Interface Builder as top-level objects, and are IBOutlets of the File’s Owner View Controller. Technically, it’s one big scroll view but I’m using this design to provide some layout flexibility if the client wants to reorganize sections, and I thought it would be cool to have the dynamic scrolling of section headers, too.
Since I want the IB objects to define the layout, I determine the height of each row based on the view’s frame:
height = CGRectGetHeight( self.playerStatsCell.frame );
The value for height of this cell (the last on the list–the others were fine) was a “whopping” 6.30104785e-38. What was going on here?!
Well, self.playerStatsCell wasn’t actually connected yet because I was testing (trying to test) one row/section at a time. Calling the frame method on a nil object seems like a normal thing to do in messaging-nil-happy Objective-C. But it’s not. The call is effectively short-circuited, and the temporary CGRect variable the return value was supposed to fill is left uninitialized, which is the bizarre height value returned by CGRectGetHeight.
This call is equivalent to:
CGRect frame; // uninitialized struct frame = self.playerStatsCell.frame; height = CGRectGetHeight( frame );
A simple change to the following would fix it:
CGRect frame = CGRectZero; // initialized struct frame = self.playerStatsCell.frame; height = CGRectGetHeight( frame );
(In my case, I resolved it by connecting a temporary cell object in IB.)
What did I learn from this?
-tableView:heightForRowAtIndexPath: results in “strange behavior.”I still don’t know exactly what the app was doing while it wasn’t displaying the new table view, but now I know what to quickly look for when I can’t push a UITableViewController in the future.
At some point, after I’d explained a few times why you have to write software this way on Android, I started wondering why all software, without exception, isn’t written this way by default.
As of 10.6, Apple added enableSuddenTermination and disableSuddenTermination calls to the NSProcessInfo API to allow you to implement similar behavior on the desktop. At its most simplistic description, you can inform the system your application doesn’t need to have its memory paged back in just to destroy it all–just kill the process and you will be sure it behaves properly on relaunch.
I encourage all fellow iOS developers who have already acquired a “sudden termination” design style to make note of this when developing a desktop Cocoa application; I also encourage desktop Cocoa developers to start thinking about how they would design with this paradigm, as it will be one more portable technique when and if you decide to go mobile.
(NSCache and Purgeable Memory is another new-to-10.6 mechanism I consider similar to iOS’ didReceiveMemoryWarning, only giving the OS permission to purge memory instead of it requesting you clean up.)
Want: iPod on iPad able to browse desktop iTunes à la Home Sharing. Watching WWDC videos on iPad w/o having to sync first–yum.
I received a few recommendations for Air Video and StreamToMe. I’d forgotten that I’d downloaded Air Video but hadn’t set up the server; I’d also forgotten about StreamToMe even though I subscribe to Matt Gallagher’s blog.
I fired up the Air Video Server and started it serving the iTunes U playlist. Connecting and browsing from the iPad client was simple and straightforward. Trying to stream a WWDC video paused to buffer annoyingly often–which I blame less on the software than the 2GHz Mini it was running on, which probably also had the misfortune to have Time Machine kick in at the same time. But it doesn’t seem to have a functionality I implied by the “Home Sharing” reference: Copy the video to the iPad to watch elsewhere later. StreamToMe looks to have similar features (and lack thereof) to Air Video, so I didn’t test it.
I appreciate the recommendations, I really do. But neither of these can get past the one requirement I didn’t specify: I don’t want a third-party solution. My tweet was really a passive-aggressive desire to have Apple implement this.
I have fully committed to iTunes being my central media repository. It serves 157GB of my music, 148GB of movies, 100GB of TV shows, 144GB of iTunes U videos (primarily WWDC videos) and a variable amount of audio and video podcasts. As a result, I don’t have many files in formats foreign to iTunes, which both these applications seem focused on solving and I expect they handle admirably.
Both of my AppleTVs can access any file in the desktop’s iTunes library, even though with 40GB and 160GB drives they obviously can’t hold copies of everything. (True, I can’t instruct an AppleTV to copy files to itself, but I don’t feel the desire to pick it up and take it elsewhere, either.)
My iPad cannot access all the files.
My laptop can browse any file on the desktop’s iTunes library; thanks to Home Sharing it can copy any file just by dragging it to the local library. It can even browse other libraries that are shared on the network.
My iPad cannot copy files to its local library, or browse other shared libraries.
The “digital plumbing” is there in DAAP and Home Sharing to make this happen, but third party developers are left to write their own servers to support their clients. I have no reason to distrust InMethod or Matt Gallagher–and I’m pretty sure that either of them can write a better server than I ever could–but each additional server increases the likelihood of conflicts and security problems, so I don’t want to install and maintain additional, practically redundant servers.
I want a digital hub; one machine serving the same media in different ways is not a hub.
During the iPad announcement, Steve Jobs positioned the iPad as a third type of device “between a laptop and a smartphone.” In my experience, that’s an astute description. In regards to media handling, though, I feel the iPad still behaves much more like my iPhone than my MacBook Pro.
]]>
Download the Corporation Unknown configuration for Accessorizer.
At a previous employer, we ran into issues where newcomers were confused by Objective-C’s memory management, especially the differences between using properties (and dot notation) and directly accessing the ivar. As you might expect, this led to many memory-related problems. I’ve long been a proponent of only using accessors to access a member unless you have a darn good reason. (And Cocoa’s ? automatic key-value observing makes it even more difficult to have a good reason not to.) In order to visibly identify accessor-vs-direct access, we instituted a naming convention to make direct access look wrong: ivars are named with an underscore prefix (“_ivar”) and properties are not. To make this even more obvious that ivars are implementation details, we declared them @private.
You may disagree with this methodology; that’s fine. But without this context, you might have a hard time understanding my configuration decisions–and why Accessorizer especially rocks in this setup.
When I first started using Accessorizer, I thought of it as a code generator, and it’s hard not to chafe at your disagreements with how code generators generate code. I’ve found that thinking of it as a code template generator makes it easier: Generate the majority of stuff you use, omit the stuff you don’t normally use, and be comfortable with the knowledge that you will regularly have to tweak its output–it’s still better than writing it from scratch every time.



Not much to say about these settings other than “Use Defaults Table”. They don’t come into play very often, since I mainly use @synthesized properties but these settings work for me when I don’t. To see the effects on generated code, temporarily switch your properties generation to @dynamic with “generate getter/setter” checked and Implementation being generated–changes will be reflected as you make them.

I’m not sure why, but I still tend to write my own init methods. Someday I’ll explore using Accessorizer for this and Undo registration more fully; until then, you’re on your own.
The defaults table is used to override the “one size fits all” property generation based on the ivar’s type. I have configured every superclass of “NSMutable<Something>” to default to “copy” instead of the default “retain” in order to avoid holding reference to a mutable object when I’m expecting immutable. (This is explained in Apple’s documentation.) I don’t even use some of these classes, but when I do I don’t want to be surprised. I’m always free to edit the declaration on a case-by-case basis, but this is the behavior I want ninety-some percent of the time.
Another fun feature of the Defaults Table is the “generation” setting. If you have a class type whose behavior you tend to override often, define its generation as “dynamic”. Every time you use that class type, Accessorizer will generate an @dynamic declaration–and the accessor methods for you to use as a starting template. (This is why I check the “generate getter/setter” in the Accessor tab even though it normally won’t do anything.)
I don’t really use this tab, and I don’t believe any of it gets saved into a configuration set since it’s primarily for point-and-click tweaking of behavior on an ivar-by-ivar basis.

As I mentioned, I prefix my ivars with an underscore, so here is where I define that. By defining my ivar Prefix as “_” and Suffix as “none”, Accessorizer automatically recognizes that underscore and strips it when declaring the property. It also properly declares the backing ivar in the @synthesize directive.
Most of these tabs are more hands-on generation of code. You need to enter a class name, and it will generate code right there–I don’t use these as frequently as accessor generation, and you can tweak the layout more directly when you do need it. At some point, I may have changed my settings from the defaults you would encounter in a new install, but I don’t really have strong suggestions for you here.
]]>