The joys of writing code

Yesterday and today I decided to tackle an issue in some of my code that I wrote for a client. This wasn’t a huge chunk of code, but how it worked bugged me and was actually going to affect my current project. This chunk of code, unfortunately was in a kernel extension (KEXT) and is extremely hard to debug. Each time I made a slight mistake, my machine would crash and I’d have to restart. After 4 or 5 times doing things, I decided to get smart and use one of my test machines. Luckily one of the machines already had Xcode on it. Crashes on this machine aren’t that bad as I can work on my main machine when it is restarting and it restarts much faster as I don’t have so much junk on it.

Anyway, after fighting with the code for something like 8 hours, I got it working how I wanted. Yeah! This is one aspect of development that I truly dislike; kernel extensions are hard and even if I was paid more, I wouldn’t want to do them. In this particular case, the kernel extension is very minor because I convinced the client to change their firmware to make it minor. It didn’t take much convincing as the more complex a kernel extension is, the more prone it is to crash (and take down the entire machine), require changes for the next OS update, and cost significantly more to write.

So while I can tackle just about any code on the Mac, will I is another question. In this case, it was worth my time to investigate this issue.

My first iPhone app has been released!

My first iPhone application, GrandDialer, is now available on the App Store. Basically it allows GrandCentral users to call people and have their GrandCentral number appear on the caller ID. The reviews have been pretty positive and I’m quite excited. It is free and seems to be getting a bunch of downloads (the audience is quite limited at the moment because GrandCentral isn’t accepting new users). If I charged for it, would people pay? I think some would, but not everyone.

The App Store is a bit of a mixed bag; the centralized distribution is cool. The waiting for Apple to post it is a downer; the review system needs lots of work (the only way I can respond as a developer is to post a 5 star review which just isn’t right).

I have some idea on what to add to the app, but I’m quite limited in what is exposed from GrandCentral.

If you have a GrandCentral account and an iPhone/iPod Touch, go grab a copy of GrandDialer!

Finding bugs automatically

A colleague pointed me at a tool called LLVM/Clang static analyzer which is supposed to find bugs in code automatically. I was skeptical at first as how could it do it? Well, after running it on a few projects, I quickly became a believer! While it finds some stuff that isn’t technically bugs, it did catch a number of memory leaks that I’m actually ashamed to have found in my code. Some of my old crufty code had leaks in it and a few places where I misunderstood memory allocation caused me to revisit them (turns out that most of the sample code I’ve found dealing with NSManagedObject subclasses also has memory leaks). I’m going to make sure to run this on all my projects; I need to put a better front end on it so I don’t always have to type in the command and remember the syntax.

It took me awhile to get it to say that some of my projects were “bug free”; it uses function names as indicators as what should retain memory and what should not. There was a function GetSomeValue which returned a CFStringRef that had to be released by the caller. CF convention says that the caller does not have to release an object if the function name has get in it. I had to switch the name of the function to CopySomeValue as CF convention says that the caller must release an object that has copy or create in it.

New features for newer operating systems

I’ve written a number of times (I think) about how long should I support an older OS. I’ve also said that I’m not abandoning Tiger users, quite yet, but I may have mentioned that new features are likely going to be Leopard only as required to make things easier. In the recent past, I’ve implemented 2 Leopard only features; the first is support for Image Capture scanners. Image Capture seems like a broken framework that might be fixed someday. In the meantime, the only way for me to reliably test and get things working is to require Leopard.

The other feature (which I just finished today) is allowing a library to be encrypted. The approach I took was to create an encrypted disc image and shove everything in that. Encrypted disc images are supported on Tiger, but one of the slick features in Leopard is a sparsebundle. What is a sparsebundle? Well, it is a growable disc image that has “bands”. This means that if you modify a few files in the disc image, only the necessary bands are updated. This is absolutely necessary for backups otherwise each time a user touched a ReceiptWallet library, he’d have to backup the entire disc image (backup apps do the right thing; it isn’t a manual process to copy the bands). With one of my libraries approaching 1 GB, that would be a complete waste of time. Time Machine uses sparsebundles for the Time Capsule and if it is good enough for Apple, it’s good enough for me! So, I’ve disabled encryption on Tiger. I’m sure that some people won’t be too happy about this, but doing encryption another way would have taken significantly longer with no true reward.

Everyday, I look at the statistics I collect on what operating systems users run. The large majority run Leopard. In the graph below, you have to make one big assumptions as the data is anonymous so users that check for updates all the time (more than the default once a day) will get recorded more than once, and that is that Tiger and Leopard users check for updates at the same rate. The actual numbers are irrelevant; it is the trends I look at and the ratio of Leopard to Tiger users. The blue and red lines represent the most recent versions of Leopard.

UserData.png

Memory leaks, oh my!

Even though I’ve been using Xcode for something like 5 years, I learn something new about it and its related tools all the time. This week I started playing with Instruments and the Leaks tool in particular. I was horrified at the number of memory leaks I found in ReceiptWallet. While they weren’t large, I’m ashamed that I had any (there were maybe a dozen or so). It also showed me that some of the system libraries I’m using (in particular TWAIN and Image Capture) also seem to have memory leaks. I feel much better that I squashed the leaks. They probably won’t affect users, but having memory leaks is just bad.

EPSON, grumble, grumble, grumble

This weekend I finally had a chance to sit down with the EPSON CX9400 I picked up on Thursday. After hours upon hours of attempting to debug ReceiptWallet and figure out the problem, I finally came up with a workaround. It appears that the EPSON TWAIN data source doesn’t close a few of its resources when the data source is closed. Then when the data source is opened again lots of stuff has taken place since the last scan potentially causing the data source to lose track of its resources (or maybe Carbon doesn’t like trying to open the same resource more than once by the same plugin). In any case, I worked around this by not closing the data source for any EPSON scanner. I really, really dislike this solution, but I went through a lot of my code and tried removing chunks to see if they caused the issue and then eventually discovered that if I started a scan, closed the scan, then showed the thumbnail view (I normally show the list view), it would crash. So all the code I tested to see if it caused the crash really led me no where.

So, this proves to me (beyond a reasonable doubt) that the EPSON scanner driver is a piece of junk and causes lots of problems for ReceiptWallet users.

While I’m beating on EPSON, I decided to grab a screenshot of their latest user interface. This is 2008, not 2000 when I bought my last EPSON scanner. Can we at least get the buttons to be nice OS X buttons and use fonts that don’t look like crap? This UI is completely unacceptable; it’s kind of interesting that the Apple store doesn’t sell any EPSON scanners or all-in-one devices (at least the online Apple store).

I recommend that Mac users stop buying EPSON devices (unfortunately I had to buy one to test) until EPSON decides to spend some money and fix the drivers. They are in such sorry shape, it isn’t even funny.

I feel so dirty

I decided to purchase an EPSON scanner to maybe workaround issues with their drivers and ReceiptWallet. I have an old Perfection 1250, but the drivers aren’t universal binaries and I wanted to give EPSON a fighting chance to make it back on my list of acceptable scanners. So I saw that Fry’s had a few on sale and purchased the EPSON CX9400. I feel so dirty purchasing the scanner as I’ve said so many bad things about EPSON. I unpacked the scanner and said “oh, this is a pretty scanner”. My wife laughed at me as I described a printer as “pretty”. It looks well made and it might replace my old HP OfficeJet 6110xi for faxing and copying.

I installed the drivers from EPSON’s site (I chose this model as it is current and has Intel native drivers) and away I went (the download was only about 20 MB vs HP’s 100+ MB). I started up Image Capture and was pleased to see that Apple’s TWAIN Bridge let me use the ICA scanning dialog instead of the EPSON dialog. Next I tried ReceiptWallet. It scanned on the first try, but crashed on the second try. Wow, that’s what people have been telling me. The crash clearly looks like it is in the driver, but I’ll take a stab at working around it as it will help many ReceiptWallet users. In addition, if ICA works acceptably, I might turn that back on as an option in ReceiptWallet. The TWAIN UI for the EPSON scanner still looks like crap, but if it works, then ReceiptWallet users may be happy.

Where is ReceiptWallet going?

The other day I was chatting with someone that I work with and he mentioned that he and his brother would like to develop a software product. As part of the conversation, he asked if I’d sell ReceiptWallet? That’s a good question. I started ReceiptWallet out of my own frustration really with no idea how well it would do. Now, it is a decent portion of my business and I still feel very passionately about it. That still doesn’t answer the question, would I sell? If there are enough zeros on the check and the terms are right (I’d want ReceiptWallet to continue on and be developed), I’d say yes! Some “indie” developers would never sell out and just like going at it alone. For me, unless I grow my company to have other people handle support and sales, ReceiptWallet will continue to consume me. Someday I’d like to not have to worry about ReceiptWallet. Is that day coming any time soon? No. Am I giving up on ReceiptWallet? Absolutely not. I work on ReceiptWallet almost everyday.

Having my own software product is nice in some ways, but it also eats up a lot of time due to my desire to create a product that I love.

Don’t worry about ReceiptWallet going away; I have some cool ideas for the future. Of course, I can’t guarantee what or when will be in there (until a product ships, no one can know what a product will contain despite reassurance from developers).

Good API ideas gone bad

Back when I started writing ReceiptWallet, I wanted to add scanner support and the easiest way looked like I could use Apple’s Image Capture (ICA) framework. This worked quite well for the first scanner I tried, but the second one only scanned in black and white or had some other problem. So, I gave up on that, learned enough TWAIN to get ReceiptWallet working with most scanners that had TWAIN drivers. I was quite content for 1.5 years (except for the crappy scanner drivers and crash reports I regularly received). Last week I was contacted by a developer who asked me if I was going to support ICA because some newer scanner drivers were going to be written around ICA. I already had ICA code in ReceiptWallet (I actually tried again right before ReceiptWallet 2.0 was released), so I took a look at it. Well, there is either a problem with my scanner or ICA in Leopard (10.5.2) as I can only scan in black and white. Furthermore, there is a really simple function, ICAImportImage, that should reduce the amount of work I have to do and presents a standard user interface.

There are a few major problems with this interface. The whole area near Scan To Folder is unnecessary if it is called from within an application. I don’t want the user to specify where it goes, the format or automatic task. The second major issue is if I change Scan Mode to Flatbed (even though I have a sheet feed scanner), parts of the UI dim and I have to quit the app (same thing happens in Apple’s Image Capture application).

So while this is great in theory (I’ve seen one app use this and apparently not care about the issues), it is a poor user experience in any app other than Image Capture. I’ll write up a bug for Apple on this, but who knows when it will get fixed. As for my other issues with ICA, I opened an Apple DTS incident and some of my issues were confirmed as bugs. Wow, that makes it almost impossible to use ICA as I found several bugs in just a simple use of the API.

Will Apple fix ICA? Hopefully. When? I don’t have any clue. My hope is that it is sooner rather than later.

Threading rears its ugly head, again

It seems to be a recurring topic here on my blog, threading. I was asked to look at a problem for a client yesterday and discovered a very subtle threading issuing (I actually didn’t create it, one of the other people on the project created the problem when he added some code). Basically in order to show progress while the app is doing stuff, some code is executed on a separate thread. However, the main thread basically spins in a loop using something like:

while (threadRunning)
{
	NSDate *newDate = [[NSDate alloc] initWithTimeIntervalSinceNow:0.05];
	[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:newDate];
	[newDate release];
}

The application uses CoreData for managing data and the second thread accesses the CoreData store. You would think that the above code blocks the main thread from doing anything while the second thread is running, but like my issue with NSTask, the main thread is actually doing something. In this case, the UI is bound using Cocoa bindings to the managed object context and the secondary thread was also using the same managed object context. As explained in Apple’s docs on Core Data multi-threading, you could get a deadlock when 2 threads are accessing the same managed object context at the same time. Bindings hid the fact that they were talking to the managed object context. I should have realized this, but I didn’t.

Will I ever learn about how to get threading right?