Goldenseal Pro- Memory Sleuthing (Aug 24)

Last week’s switch to ARC (Automatic Reference Counting) seemed to go without a hitch. Our staff was cruising along, finishing up the Preferences window and a few other details. Then, we went to edit a list on Wednesday, and the app crashed. It never did that before.  Xcode usually shows a ‘stack trace’ that explains what went wrong, but this one only had the program entry point. That’s a very hard crash.

A while back I mentioned that the completion date for Goldenseal Pro depends mostly on how many curve balls the Cocoa framework throws at us. Each is different, but here is how we are handling this particular problem.

When there are no clues, the first thing we do is to step through the code to see exactly where it goes wrong. The process can be tedious, but usually it ferrets out an obvious error. This one turned out to be tougher. Sometimes the window would crash immediately. Sometimes it would open and stick around for a few seconds, then crash. Sometimes it would wait until we clicked something. There was no smoking gun in the code.

That delay made it seem like it might be caused by ARC deleting something prematurely. Sure enough, turning off ARC made it work OK again.

Apple has several diagnostic tools that can help with memory errors, including something called NSZombie. We tried them, and discovered that the window itself was being deleted too soon. Very odd. Nothing in the code should have done that. We stepped through the code many times, but didn’t find a smoking gun.

98% of the time, when something doesn’t work we can figure out why, and make a fix that makes sense. Then there is the other 2%, where our staff is totally baffled, and has no idea what’s going on. This is one of those.

One approach that sometimes helps is to go back to older versions and see if they also break. Finding the date when things go bad really narrows down the possible culprits. Unfortunately, older copies also work fine without ARC, but break with it.

Next step was to start deleting things from the window. That usually narrows the problem down to one specific control. Except it didn’t. The app crashed, even with everything removed.  Very odd. Along the way, there was an error warning for a button that was deleted last year. Also odd. A search in the code didn’t turn up any mention of it, but Xcode thought it was still there. That suggests some sort of file corruption in Xcode’s layout data. Why it would only break under ARC, we have no idea.

The list window was the very first Cocoa we worked on, almost two years ago. We made many mistakes and changes, so it is the most likely file to be corrupted. The solution is to just build it again from scratch. That’s on the agenda for today. We will add a few things at a time and test it frequently.

In general, the goal is to have very few changes made between working and failing versions. Then it’s easier to see what’s wrong.

Meanwhile, if we turn off ARC, lists work fine. If we turn it on, everything else still works fine. So we added some code to make it easy to switch ARC on and off. Now it just requires one line of code, instead of 100 changes. That way we can proceed productively, despite this curve ball.

If the rebuild doesn’t fix it, this may be the kind of problem where it’s best to just give up for a while. Sometimes an answer appears out of the blue, weeks or months later. Or, sometimes we accidentally fix it when we fix something else.

To be continued…

Dennis Kolva
Programming Director


Goldenseal Pro- Memory Management (Aug 18)

Our staff spent the past couple days updating Goldenseal Pro to use ARC (Automatic Reference Counting).  It’s a nifty feature that is Cocoa’s third generation of memory management.  We actually thought it was already turned on by default. But, while checking some other compiler settings this week, we discovered it wasn’t.

Memory is a big deal to programmers. As Goldenseal runs, we create thousands of objects. Each is a chunk of memory that stores some data and does tricks. We give each object a name, then the operating system decides where it will live in RAM.

In C++, we need to decide when each object dies. If we kill it too soon and try to use it after it’s dead, Goldenseal will crash. If we forget to kill it, there will be a memory leak. Accumulate too many leaks, and the app will consume more and more RAM. Eventually the program will get very slow. It may even consume all available memory and crash.

Fortunately, modern C++ has many tools for managing memory, to make sure each object is deleted properly. They help Goldenseal to leak very little, and almost never crash. Some other software is not so careful. For example, most web browsers are very leaky. Use them all day, and they will gradually use up many megabytes or even gigabytes of memory.

Cocoa used to require manual memory management, similar to C++ (but without the modern tools to help). In the mid-2000s it added garbage collection (also a feature of Java and many other programming languages). Garbage collection prevents leaks by periodically checking every object, and killing it if it’s no longer being used. That prevents leaks, but also can be annoying. If you ever have an app suddenly stop dead for several seconds, its garbage collector probably is “emptying the trash”.

Apple added ARC in 2011. It automatically kills each object when nothing else uses it any more. For example, dozens of objects die whenever you close a window. It makes memory one less thing to worry about.

For ARC to work, we had to add a __bridge keyword, every time we convert between C++ and Objective-C.  The compiler colors it bright green. It’s actually kinda nice to have it in the code. The conversions are risky, and anything that makes them more obvious is a good thing.

In general, our staff spends a lot of time looking at brightly colored text. Source code is a huge mass of comments, objects, functions and programming commands. It can be overwhelming. A bit of color coding really helps.

Dennis Kolva
Programming Director

Goldenseal Pro- Combo Boxes (Aug 3)

How to classify things is a problem in both estimating and accounting software. It’s particularly difficult for job cost accounting. Expenses come in randomly, and you have to match them to vendors, jobs and categories.

One important principle in interface design is that people can recognize something much faster than they can recall it. It’s one reason why buffets are popular. No need to remember General Tso’s name. Just scoop and eat. 

Typically, software uses popup buttons for list choices. You click, see the list, and then choose what you like. However, that approach doesn’t work well for long lists (over 30 items). They get too hard to navigate. Popups also require a mouse-click, which is inconvenient when data entering from a keyboard. 

Bruce Tognazzini, the author of Apple’s Human Interface Guidelines, proposed a solution to both problems in the early 1990s. It’s a text field you can tab into. But, when you type, it shows a scrolling list, and jumps to the nearest match. Tab out or hit the enter key, and it selects that item. If you’re not sure what to type, you can also click and scroll until you see what you want. He called it a disambiguating field. At the time, FileMaker had a lookup field that was sorta like that, but his version was better.

In our older MacNail software, we didn’t even have popup menus. Users had to type in a number or letter code to do job costing. Finding a better way to handle long lists of jobs or categories was one reason why we abandoned Excel, and built a stand-alone app in C++. We copied Apple’s specs but called them clairvoyant fields, slightly less vague than disambiguating.

Programming clairvoyants required a text field, plus a temporary table for the list, plus a popup button to choose items with a mouse click. Interactions between them were complicated. Users could do many things with the mouse or keyboard, and the code had to handle them all. Lists might contain thousands of items, so it was challenging to get decent performance on 1990s hardware. We spent a full programmer-year getting clairvoyant fields to work right.

Since that time, both Macintosh and Windows have added a combo box control. It’s almost identical to the original disambiguating field, so we were delighted that we could use them for Goldenseal Pro. Kinda like, we had to build them from scratch back in the 90s, but now you can buy them at Walmart.

It took a few hours to get combo boxes working on Windows. A few days for Macintosh, but we ran into a problem. If you typed something not in the list, it just added that text. OK for some uses, but not for job cost accounting. You don’t want to start posting expenses to the Snith job just because you made a typo.

Apple’s web page for combo boxes said it was possible to restrict them to existing items. Our staff couldn’t find sample code to do that, and couldn’t figure how to make them work right. Eventually we built a replacement from a text field, temporary table and popup button, just like before.

Doing it that way was still just as complicated. Three or four times we got frustrated, and went back to the Cocoa combo box to try again. Then we kept reverting, and gradually perfected the built-from-scratch version.

A few weeks ago, we posted to Apple’s Cocoa-dev mailing asking for help.  Unfortunately, nobody there knew how to make them work right, either. Almost everyone insisted we should use popup buttons instead of a combo box. Out of desperation, we actually tried popups as suggested, but most of their old flaws still remain.

So, the dream of easy Mac combo boxes was just a dream. Windows has a simple yes/no option to restrict to existing, and you’d think that Cocoa would do the same. But, nope.

Building combo boxes from scratch has taken some time. Fortunately, after a couple more weeks of effort, they are working well. Unfortunately, they will look slightly different between Mac and Windows, and we may need to give them different names.

Dennis Kolva
Programming Director