Monday, December 30, 2013

How to deal with "QuickBooks has encountered a problem and needs to close."

It's 2 days before the end of the year, a time for bookkeeping and regulatory filing, albeit not a lot of time left to meet the end-of-year deadlines, when this happens when launching QuickBooks:

Trying again produces the same error, over and over again. Then panic sets in, did I just lost all my financial information ? Why is this happening ? Probably my company file got corrupted, and QuickBooks can't deal with it. More on this later. Let's fix it first.

One way to recover from a corrupted company file is to restore it from a previously saved backup. If you don't have a recent backup ready, my method won't help you. First I need to locate the backup file. QuickBooks has the habit of moving the location of backups, as you upgrade to newer versions, so my best bet is to do a search for files with the extension ".QBB":


Alternatively, you may have a copy of the backup saved "in the cloud" - highly recommended in case something happens to your computer - not necessarily to use the online storage offered by Intuit. Any alternative will do.

Trying to open a local backup by double-clicking the file produces this message:


Yeah, thats very helpful, Intuit. I'm having problems exactly with opening QuickBooks, which by default will always try to open the company file. If that's corrupted, I'll keep getting the "encountered a problem" error message (meaning that in fact the program has crashed). To get out of that dead-end we could first locate the company file (should have the extension *.QBW - if you don't know it's location you can search, as I did above for *QBB).


 Then we can rename it to something else:


Now if I try to open QuickBooks I see:


Now we're getting somewhere. Click the "Open or restore an existing company" button:


And choose the "Restore a backup copy":


In my case I'll use a local backup:


Here QuickBooks will try to hold my hand:


But the original (corrupted) company file would have been already renamed, so I'll just use its original name:


Next, sweet victory:


We're back in business. Just remember, because this was recovered from a backup, some of the most recent transactions, since that backup was made, will be missing. You'll need to enter those again. That's why it's good practice to perform backups often.

Now let's talk about why this happens, and how Intuit could have dealt with it in a better way and not have us jump through all those hoops. I'm a software developer. It's right up my ally.

In my case the problem happened because I inadvertently launched QuickBooks twice. My computer had just rebooted after Microsoft installed a bunch of updates, and now was acting pretty sluggish (thanks Microsoft !). My initial attempt to open QuickBooks seemed to go nowhere, so I tried to open it up again. Upon closer inspection, using the task manager, I was able to see 2 instances of the QuickBooks app running. Uh-oh. Shortly after came the error message about the crash.

So the first failure of Intuit was to handle this common scenario, of trying to open the program multiple times. Obviously, when QuickBooks opens it must be writing something in the company file, and having multiple instances open causes them to step on each other's toes and results in corrupting that file. There are plenty of ways to ensure exclusive access to a file by a single process - pretty basic stuff - which Intuit failed to implement.

There are other ways in which the company file may get corrupted, for example if something happens with the application/operating system/computer while the file is in the process of being written. There are ways of dealing with those scenarios too, and indeed a well engineered app should try to prevent errors and data corruption. But those may happen anyway, despite our best intentions. So the next step would be automatic error recovery. Here Intuit fails again. They pretty much try to open the same corrupted file each time the app launches, resulting in crashing over and over.

A better way would be to catch that error and not let the app crash, or at least on subsequent launches detect that the app had previously crashed, and enter a recovery mode. The recovery could be made from a redundant copy of the company file or from a backup, as I manually did above.

These are 2 principles worth observing when doing software development. First do your best to prevent errors. Then assume that some errors will happen anyway and ensure that you can recover from them graciously.

Saturday, May 25, 2013

How to fix PDFs that appear with colors too dark or too bright when viewed on iPad or iPhone.

In some of my iOS projects I had to display PDFs of documents originally intended for print format. Some of those PDFs would appear horribly on iOS devices, with colors messed up. It was a pretty surprising behaviour, which I initially attributed to bugs in Apple's PDF rendering code.

My first approach to getting around such problems was to use a server-side component powered by Ghostscript to convert each PDF page into an image, that would show up in the right colors, and display that. The advantage of this approach is that it can be fully automated. The disadvantage is that images may show up poorly (pixelated) when zoomed in, depending on their pixel density.

Upon investigating this problem further I discovered a way to fix this problem at its root, that is the source PDF document. Unfortunately it can't be automated easily because it involves running Adobe's Acrobat tool. In the absence of a public API to run that conversion programatically one has the option of using workflow-recording tools like Apple's Automator to drive the Acrobat automatically. While that approach may work, it would be hard to scale in a cost-effective manner.

Another option to handle this may be to use iText to automatically convert CYMK profiles to RGB, or if that's not possible, to at least detect the presence of CYMK profiles and alert the user about the need to convert the PDF manually using Acrobat.

Tuesday, May 14, 2013

So we had the www for a while. What's next ?

The dawn of the web introduced us to URLs starting with "http://www". For those old enough to remember those days of Lynx, Mosaic, and Netscape, "www" was true to its meaning of "world-wide web". Suddenly anyone connected to the Internet was able to reach out to any remote place in the world, also connected to the net, and browse the information published there. Powerful.

Since then a lot has changed. The devices we use to access the net had moved from our desks to our palms, and soon to our glasses, and with the mobility they afford, the Internet access got a new dimension - that of context, or location. So in addition to what's out there (www) now what's over here becomes an interesting question. Perhaps some new URLs, like "http://here" and "http://now", start to make sense. Seems that I'm not the only one thinking so. Nokia appears to be doing something like that with http://here.com. If face recognition becomes a feature of Google Glass, then a "http://you" makes sense too. I'm probably stating the obvious here, but what I'd like to see is more of these 2 things:

1. The ability of users to freely add and annotate the content presented. Think of "Augmented Reality Wikipedia". Like "digital graffiti" curated through a vote-based meritocracy, or by applying a filtering based on what your contacts on social networks think of that content.

2. More mash-ups. With the growing number of web services (over 9000 APIs as of now), and the continued move toward a more semantic web, the ability to mash things up should continue to grow.

It'd be interesting to see how all this will unfold, and maybe even contribute to this vision. Such projects, once they pass a critical mass of adoption, they tend to snowball fast.

Friday, May 10, 2013

Rendering office documents in HTML - an idea whose time has come

A while ago I was working on a project that needed rendering PDFs on iOS. There are several ways to do that. On iOS, that is. My client wanted a solution for Android too, and was complaining about the lack of similar capabilities there. Since Android wasn't one of my areas of competence at the time I wasn't involved with that effort directly. However I kept hearing about the need to use some 3rd party, rather expensive, libraries.

So naturally it dawned on me this idea: why don't the "owners" of the PDF format, Adobe, provide a cross-platform viewer. The natural solution would be an HTML based approach, since virtually all popular platforms provide a way to display HTML. At the time I was thinking that the capabilities provided by HTML 5 and CSS 3 should be enough to accomplish the "print-quality" level of rendering offered by Adobe's Acrobat Reader or Apple's Preview. Since Adobe wasn't doing much about it, it seemed a pretty good opportunity. Turns out that wasn't such a bad idea. In fact folks at Crocodoc were banging at it since 2006. Today was the payback. Good for them.

I only heard about them today. A brief glance at their API shows that right now it fetches the documents from some servers, where they're processed and converted from PDF to HTML. With this dependency on a server-side component it doesn't seem to have support for offline viewing. I guess one could hack around and save the generated HTML and all the referenced components (images, CSS, and what not), but that may be a brittle solution. With their new owner I'm sure they'll keep improving their technology and this may well become a compelling cross-platform document rendering solution.

Saturday, May 04, 2013

Caveats of using MPMoviePlayerController

For a recent iOS project I had to play some videos, embedded in a subview of a larger view. One way to achieve that is to employ the MPMoviePlayerController. At first glance that component seems easy enough to use. Folks at Apple are trying to help by providing the following code snippet, right there in the official docs:

MPMoviePlayerController *player =
        [[MPMoviePlayerController alloc] initWithContentURL: myURL];

[player prepareToPlay];

[player.view setFrame: myView.bounds];  // player's frame must match parent's

[myView addSubview: player.view];

// ...

[player play];

Right on. I'm adding this stuff to my app, and ... nothing happens. Nothing plays, just a black rectangle where the video player was supposed to show up. My first reaction was to look if they have a complete sample project that I could play with, and learn how to use the API. They do. I open it and it's using manual memory management (pre-ARC). Yuck ! Still I look there and see that they're using notifications to observe the state of the player. That sounds like a good way to debug what's going on. I do the same in my code. None of the notifications get called. What the ... ?

On a 2nd look at the code above, it becomes clear that in an ARC project, like mine was, the player local variable will be gone at the end of its enclosing scope. No wonder that nothing happens. The player must be kept alive through a strong ivar, or property. Doing that fixed my problem. So Apple's code snippet is pretty bad. It would have worked in the pre-ARC projects, albeit by leaking memory, but obviously this stuff was never updated for ARC.

Luckily I have plenty of experience doing manual memory management, and I can handle old code bases, like so many of Apple's code samples are. For now I'll inform their docs team of the problem.

Saturday, April 27, 2013

Keeping the code clean of warnings helps your productivity

In some Fortune 500 companies I worked we had an official policy of 0 compilation warnings allowed in the code. That was a good practice that saved us of many troubles. Since then I try to follow that practice in my projects.

Let's see an example:

        NSLog(@"Hello, World!");
        
        int i = 1;
        switch (i) {
            case1:
                NSLog(@"OK");
                break;
        }

If I placed this code in a project with the default settings created by Xcode, the result wouldn't output the "OK" string, due to the "case1:" typo which transformed the "case 1:" case statement into an unused label. The compilation wouldn't produce any warning. Neither would the static analyzer.

You can however catch such problems at compile time, by changing the default settings like so:


This enables all warnings. The following setting treats all warning as errors:


If I now try to compile I get this error:


Catching this bug at compile time is much better than later when the app may have been released.

Another useful setting to have is this:

which runs the static analyzer on every compilation. I found this combination of settings very useful to smoke out bugs shortly after they have been introduced.





Saturday, April 20, 2013

Unexpected side effect of fast enumeration in Objective-C

Fast enumeration is a relatively new capability in Objective-C. For a thorough survey of all the ways one can enumerate through a collection, you can see this post.

In a recent project I had a code sequence like this (modified here for illustration):


        NSArray *array = @[@1, @2];
        NSNumber *number = nil;

        for (number in array) {
            NSLog(@"number: %@", number);
        }
        
        NSLog(@"Last number: %@", number);


My expectation was that at the end of the for loop the number variable would hold the last value of the array. Here's what I get instead:


2013-04-19 17:13:06.223 FastEnumBug[49016:303] number: 1
2013-04-19 17:13:06.240 FastEnumBug[49016:303] number: 2
2013-04-19 17:13:06.241 FastEnumBug[49016:303] Last number: (null)


Strangely the value comes back as nil. Which is what it was initialized to before entering the loop. Could that be the case ? Let's try this instead:

        NSArray *array = @[@1, @2];
        NSNumber *number = @100;

        for (number in array) {
            NSLog(@"number: %@", number);
        }
        
        NSLog(@"Last number: %@", number);

which produces:


2013-04-20 18:47:34.209 FastEnumBug[62468:303] number: 1
2013-04-20 18:47:34.212 FastEnumBug[62468:303] number: 2
2013-04-20 18:47:34.212 FastEnumBug[62468:303] Last number: (null)


Nope, I still get nil, not the @100 value at the entry of the loop. So it seems that fast enumeration blocks  reset the value of the iteration pointer in the outer context back to nil. This is, at least to me, unexpected. Maybe it's a bug. I'll see what Apple has to say.

Saturday, March 23, 2013

Charging for wireless services by auction

I've been thinking about this for a while now. All mobile network operators have a rigid price structure, in some markets, like Canada, with outrageous costs. Yet when certain areas of the network are idle, due to low traffic, the network equipment remains unused, and is producing no revenue. It strikes me as    a very inefficient way to allocate and manage resources. I believe an auction-based model, where available capacity is up for bidding would be more efficient.

Once the costs of laying out a network have been sunk, the ongoing cost of operations should dwarf the initial investment, and should allow for a wide range of pricing to make economic sense. That is, the cost of allowing access to a spare channel of communication between a mobile device and the network shouldn't be much higher than the cost of keeping that channel unused, on stand-by. I'd venture to guess that most of the additional cost is for the energy used to power the transmission.

Hence the opportunity, if I'm a customer in the right place at the right time, and the cell covering that location has plenty of spare capacity at that particular time, I should be given the opportunity to get access to the network at a rate lower than the going rate. Whereas I would almost never pay the $10/GB going rate, I would be willing to pay a lower price. Because of the rigid pricing, however, this opportunity goes wasted. I don't get to use the service, the service provider doesn't get paid. Lose-lose scenario. Flexible pricing would turn it in a win-win.

Conversely, sometimes you might find yourself in an area that's highly congested, with no physical ability to accommodate everyone, even at the going rate. Some calls will need to be dropped. Flexible pricing would be a way to guarantee a connection for the higher bidders. So sometime I would be willing to pay above the $10/GB rate.

Such flexibility would benefit all parties. Sure there would be some complexity added to metering and billing, and some signalling mechanisms should be devised for dealing with the bidding process, but the gains may far outweigh the costs. Why nobody implemented something like this, especially for pre-paid or pay-per-use plans, remains a mystery.

Saturday, February 16, 2013

UIView gotchas in iOS

In iOS the UI consists of a hierarchy of views and view controllers, linked through containment relationships. That's following the common composite design pattern, which should be familiar to most programmers. In addition there is a specific system-imposed lifecycle, which governs how all those pieces come into existence, and various callbacks that the system (Cocoa Touch) calls at specific points in this lifecycle. All this is fairly well documented, but with experience comes additional insights, and lessons learned the hard way. Here's what I discovered:

If your code relies on the coordinates of a view's frame, then your best bet is reading the frame in:

- (void)viewWillAppear:(BOOL)animated

You may be tempted to use - (void)viewDidLoad for the same purpose, which gets called earlier in the lifecycle, however at that time the frame may not have its value set accurately. I find this happening often especially for iPad. Most times I use the storyboard (and IB in the past) to implement my UIs. I usually lay it out in portrait mode only, and rely on the autoresizing mask, or layout constraints, to position everything properly. Because on iPad you can launch an app in landscape mode directly, the frame in viewDidLoad will appear as defined in the storyboard, with the size for portrait. If those values are relied upon later, that would result in problems.

This problem may also occur in obscure contexts, where one is not directly using the frame. For example in a previous post I was mentioning some weird behaviour when setting the value of a progress bar, like so:

[self.progressBar setProgress:0.5 animated:YES];

Apple took a look at it and informed me that "The view animates from an undefined state. Doing such things in the viewDidLoad can only lead to problems.".

Update:

While watching the slides from Stanford's iOS Programming course I discovered that in case that autolayout is used, instead of using viewWillAppear to get the view's geometry, one must use

 - (void)viewDidLayoutSubviews

Apparently the latter is guaranteed to be called each time the bounds of the view change, and by the time that happens all the autolayout constrains would have been processed and the geometry would have been established.

Saturday, January 26, 2013

Unexpected behaviour when calling setProgress:animated: twice in the same run loop

I found some bugs in setProgress:animated: method of UIProgressView. It seems that calling it several times within the same run loop ignores all but the last call.

For instance, I have a bar set up in the storyboard with the progress all the way to the max (i.e. 1.0). If later in the code I do this:


- (IBAction)showBug {
    [self.progressBar setProgress:0.0 animated:NO];
    [self.progressBar setProgress:0.5 animated:YES];
}



I would expect the bar to jump to 0 and then animate to 0.5. What happens instead, the bar animates from 1.0 to 0.5.

One workaround, of course, is to place the 2nd call on a separate run loop, like so:


- (void)hack
{
    [self.progressBar setProgress:0.5 animated:YES];
}

- (IBAction)fixIt {
    [self.progressBar setProgress:0.0 animated:NO];
    [self performSelector:@selector(hack) withObject:nil afterDelay:0];
}


Ahh, the trusted 0 timer. How many times it saved my skin. For instance, when mutating collections while iterating. And not only in Objective-C, I remember using it in JavaScript to work around all kinds of browser bugs. That's the advantage of having exposure to multiple platforms and languages. You learn all kinds of tricks.

Incidentally, when I was preparing the bug report for Apple, I discovered yet another, unrelated bug. Placing this line:

[self.progressBar setProgress:0.5 animated:YES];

in the - (void)viewDidLoad method of the view controller makes another mess. Now the bar, which was placed statically in the storyboard, (in my example I had it centred) it animates when the app starts, through a "genie" animation from the top-left. Nice, but definitely not what I intended.

Update: Regarding the latter bug, Apple informed me that  "The view animates from an undefined state. Doing such things in the viewDidLoad can only lead to problems.". See this post for a discussion of the perils of reading/writing the frame of a view in viewDidLoad.