Dec 22

Multithreading
Everyone has their own vision of how things should work. As you gain more experience in your craft, you become more grizzled. Well learned. After some time, you earn the privledge of passing this experinece on. Oscar Wilde said it best:

Experience is simply the name we give our mistakes.

Multi-threading in software engineering has been around for a long time. Many mistakes have been made, thankfully. From those mistakes, experience was born. Most of the engineering books talk about the essentials, and the dangers that must be respected and adhered to. But while they talk about the pitfalls of what could happen, none of them really give you great guidelines. I’ve been doing this a long time and I’ve worked with people who should not have made some of the mistakes I’ve witnessed.

Are they bad engineers?
No.

Was there a fundamental misunderstanding about multi-threading?
No.

But there are some fantastic guidelines that aren’t well-established. It seems like Brent Simmons and I agree on a lot of the same principles. He’s written a great blog post about Cocoa Threading that every Cocoa developer should read and understand. He refers to his post as his, “barely-organized thoughts on threading and Cocoa applications” but it covers the points in a concise manner.

Thread Communication Exclusively on the Main Thread

First up is his philosophy on all communication between threads taking place on the main thread. He extends this to notifications as well. I’ll add one more to that list which is KVO notifications. This is essential because UIKit and Core Data don’t like operating on secondary threads. I don’t know how many times I’ve seen

NSAssert( [NSThread isMainThread], @"This needs to run in the main thread" );

 go off because I received a notification or call from a secondary thread.

Communication between systems always happens on the main thread. (A system is one or more objects that work together.) In most cases, communication between objects in the same system happens on the main thread too.

If an object does something in the background, that is that object’s business and nobody else’s.

This extends to notifications: from background threads, I always make sure notifications get posted on the main thread. This way every notification observer can always assume that it’s getting called on the main thread.

Regarding KVO, Brent has this to say:

KVO is a trickier thing. Here’s how I handle that: anything happening in a background thread is not observable (by convention). Whatever is going on is private. When it’s time to set public stuff, stuff that could be observed, those things are set on the main thread.

Threading Methods

There’s almost as many different ways to spin off a thread as there are people in the United States. Brent and I also agree on which methods we use:

I’m very deliberate about my threading. I like Grand Central Dispatch, but for my purposes NSOperationQueue works best. The formal, easily-monitored approach of NSOperationQueue works best here. I definitely recommend against anything but GCD and NSOperationQueue — anything else (NSThread’s detach method, etc.) is too random. (Yes, we used it for years, but we have better stuff now.) (In fact, I almost never even use NSInvocationOperation — I much prefer the structure and defined stop/start of NSOperation.)

I use an NSOperation subclass that takes a target and selector in its init method. When it’s finished, it calls the target and selector on the main thread. This way the caller only ever sees the main thread — it creates the operation on the main thread, then gets called back on the main thread. The fact that the operation happens in the background is unknown to the caller: the caller just knows that it’s async, and doesn’t know anything else.

I almost exclusively use NSOperation subclasses with NSOperationQueue in my applications for the same reasons that Brent outlines. You can create multiple NSOperationQueue’s if you need different operating parameters (for example, one queue that is sequential, another queue that can operate concurrently). Making dependencies between various NSOperation’s is as simple as making an addDependency call. Plus, they can have dependencies across different NSOperationQueue’s.

Locking

NSCache seems to have suffered from poor marketing. It’s a little gem that very few people seem to know about. I’ll bet most of you have written your own class that performs much of the same functionality. I’ll take the very-well tested and used NSCache, which is also thread-safe, any day.

Locking sucks. If you have to do it, you have to do it. It doesn’t mean you’ve failed — failure would be not-locking when you really do need a lock.

There are a couple other things you can do which make sense.

  1. Use performSelectorOnMainThread to set some data that would otherwise require locking. (This is not a trick to use willy-nilly, though — typically it comes at the very end of an operation, not sprinkled throughout.)
  2. Use NSCache — it’s thread-safe.

I highly recommend you read Brent’s full article, “Some Notes on Threading” over at his site.

Written by Terry Blanchard \\ tags: , , , , , , , , , ,

Sep 01

“How can we automate our build number in this project? Perhaps a python or AppleScript?”

I get this question a lot. I contract out my development services to companies who need Mac, iPhone, or iPad software designed and developed. Many of these companies have lots of Windows developers on board full-time and contract out their Mac work so I understand that all-things Mac are new to them.

But this question always comes up. Always.

While they’re already thinking about some elaborate scripts to automate this process, I hold up my hands and say, “It’s already covered.”

I decided to blog about it because most people don’t know the name of the tool and can’t “Google” for it without stumbling across scripts to accomplish this task.

Apple includes a command-line tool called agvtool which handles my versioning needs. It’s not perfect, but it does what it needs to do and when used in a corporate environment with a build system, it’s fantastic.

What is it? In a nut shell, it’s a very focused “Find and Replace in Files” command-line tool. It searches through your program’s Info.plist file as well as the project .pbxproj file and updates them. You can even have it commit it’s changes with version control if you’re using Subversion or CVS.

The real number that needs to be constantly updated is the build number. Normally, the marketing version only changes at the beginning of a new branch or feature set. agvtool will help you out with both tasks. First, let’s tackle getting your project setup so you can display the following string in your iPhone About screen:

Version: 1.0 (Build 1)

The agvtool refers to the “1.0″ part as the “marketing version” and “1″ in the Build parenthesis as the project version. To update the build number we simply issue the following command from the project’s root directory which contains the .pbxproj and Info.plist files


agvtool bump -all

This command will change all of the build numbers, or project versions in agvtool speak, to:

Version: 1.0 (Build 2)

Want to change the marketing version to 1.1?


agvtool new-marketing-version "1.1"

Now our About box says:

Version: 1.1 (Build 2)

Cool, huh? Okay, so here’s how you setup your project to take advantage of this nifty little tool. First, we have to tell Xcode that we want to use agvtool for our versioning needs. From the Project menu, select Edit Project Settings. Ensure Configuration is set to All Configurations and Show is set to All Settings. Navigate down to the Versioning section and make the following changes:

Project Versioning Settings

Lastly, we need to update the Info.plist file. You need to set two values in, your Marketing Version is the Bundle versions string, short. If you don’t have this option in your plist file, select an item in the list and click on the + off to the far right. You can then select it from the list. The Bundle version is the build number. Set this value to match the one you placed in the Project Settings option for Current Project Version.

Versioning Plist Settings

Now, whenever you’re ready to build an official release, just run:


agvtool -usesvn bump -all

The -usesvn parameter is optional. For an official build, you’ll want to commit the files that were changed by agvtool.

Then call xcodebuild.

Earlier in the article I mentioned that agvtool isn’t perfect. Here’s what I mean by that comment. For an automated build, having a command-line tool is fantastic. However, if you run agvtool while you have the project open in Xcode, you get this:

Project Has Changed. Read From Disk?

Since agvtool went and changed the .pbxproj file while you had it open in Xcode, you get this. Simply click on “Read From Disk” and you’re back in business. More of an annoyance than a show-stopper.

Written by Terry Blanchard \\ tags: , , ,

Jul 30

You can’t just open up your editor of choice to modify the /etc/hosts file on your Mac. You can open the file without any problem, you just can’t save it.

To do this you must have super user privileges. Just being an Administrator isn’t enough. Fortunately, there’s a way to temporarily get super user privileges using the SUDO command. So I fired up Terminal and typed in:

sudo textedit /etc/hosts

Ruh-roh. It wouldn’t let me save the file. Crap. I’m not a Unix guy and VI makes my skin crawl and head hurt, but I was able to use sudo vi /etc/hosts and save the file.

So why couldn’t I get any of the GUI apps to save it?

Turns out, that you need to sudo the actual executable which is inside the TextEdit.app bundle. So the command I issued is this:

sudo /Applications/TextEdit.app/Contents/MacOS/TextEdit /etc/hosts

Voila!!

If you happen to own TextMate, then you can save yourself a lot of typing and heartache. TextMate installs a Terminal command called “mate” that allows you to perform the above sudo command. Just type:

mate /etc/hosts

BBEdit also has this capability:

bbedit /etc/hosts

TextWrangler as well:

edit /etc/hosts

Voila, again!! When you go to save your file, you will be prompted for your password.

Written by Terry Blanchard \\ tags: , , , , , ,

Jun 21

I hit a really odd bug last night. I mean, really, really odd. One of those bugs that keeps you up until 4am and you go to bed defeated. I came into the office today and had another engineer sit with me as I went through my code explaining what I was doing hoping that a second set eyes and another brain could bring some clarity.

No luck.

Everything looked good, but this very odd crash was still occurring. We were both scratching our heads. The weird part was that the program ran perfectly on the iPhone and in the simulator, as long as I didn’t have the debugger attached. The other engineer tried the build on his machine and everything worked as it should and he was able to run the Xcode debugger.

I decided to completely remove and reinstall Xcode and the iPhone SDK. Normally, you just drag a Mac application to the Trash Can and you’re good. Xcode is a little different. There’s a ton of different folders, tools, SDKs, simulators, etc scattered around the Hard Drive.

So how do you remove everything?

Fire up Terminal and type:

sudo /Developer/Library/uninstall-devtools -mode=all

Type in your password and go grab a coffee. The Uninstall process takes quite a bit of time as it analyzes every package on your machine. However, it will find and remove all Xcode and iPhone SDK components. I highly recommend you to restart your Mac before re-installing Xcode.

Written by Terry Blanchard \\ tags: , , , ,