Returning nil from init (Part 2)

16 Aug

After writing about checking for nil being returned from init, a friend pointed out that I omitted nullable annotations, as well as possibly documented usage. They also raised an interesting point about failing (crashing) early vs partially recovering – given the contrived button example.

Let’s address nullability first. I ignored mentioning nullability annotations as there is a lot of existing code in the wild that hasn’t adopted them. (If you’re writing new code you absolutely should be using them). With nullability annotations, the question of if you should check for nil being returned from init is already answered. If the API specifics it is nullable – check. Otherwise you can assume you’ll get a valid initialized object. Even with nullable annotations there’s no runtime guarantee (it’s a static analyzer warning), but you should trust the API, if it doesn’t perform as advertised – that’s a bug.

As for documentation – you are writing header docs right? Docs can, and should, describe if initialization can fail, and under which conditions that might occur. If the API you’re calling doesn’t have nullability annotations, check the docs. You might find that it’s clearly documented if initialization can fail, and if you should be checking for nil.

You should absolutely be writing header docs by the way. Your team will love you for it. Even if you’re a solo developer; future you will thank you for it.

Finally, onto the topic of crash early, catch early. I used a button class as a completely arbitrary example last time. I could have, and perhaps should have, picked a better example. It’s extremely unlikely that you’d ever want a button to have a failable initializer. But it did raise and interesting question: If a button did actually return nil – what’s the “correct” behavior? Is it better to guard against crashing, or to guard against a broken UI? I think it would depend on a number of factors – what conditions in which the crash might occur, how important the button is to the functionality, is the app doing critical work that needs to be stopped safely? During development I’d be ok with permitting a crash. You might not notice that one in a dozen times the button happened to be missing, but you’d notice a crash right away.

All this is to say, when getting a value back from an initializer, stop and think for just a second, could this fail? What happens if it does? How should we react?

Returning nil from init

13 Aug

I was recently asked why we should bother checking for nil in the code below? Shouldn’t init always return an object?

NSMutableArray *buttons = [[NSMutableArray alloc] init];
LMActivityButton *activityButton = [[LMActivityButton alloc] init];
if (activityButton != nil) {
    [buttons addObject:activityButton];
}

Nope. It’s actually perfectly valid to return nil from an initializer. In fact, if initialization fails it should return nil. It’s the preferred way to indicate initialization failed.

You’ve been (hopefully) partially adhering to this convention without even thinking about it. Every time you type the following bit:

SomeClass *someObject = [[SomeClass alloc] init];

Instead of

SomeClass *someObject = [SomeClass alloc];
[someObject init];

The second version is unsafe, because init could return nil and release its memory (or substitute an entirely different object).

Now, we could look at the source for LMActivityButton above and see that it doesn’t actually implement an initialization method; it defaults to NSObject’s init. Knowing that NSObject doesn’t actually do anything in init, it just returns self, one could argue the check for nil is unneeded. And today, one would be correct. However, nothing says that LMActivityButton won’t add its own custom initializer in the future, and that said initializer won’t return nil to indicate failure – though admittedly it would be highly unlikely / unexpected for a button to do something so complex as to fail initialization.

For me, this really comes down to good habits. It’s a good habit to check for nil from an initializer if you’re going to be doing work that expects it to be non-nil, like adding it to an array. It also serves to remind you, and others, that init can fail, and that other, more critical, places in your code should protect against it.

Race conditions

1 Aug

Race conditions came up during a conversation I had about a week ago. I tried to explain them as best I could, but I failed horribly, metaphor piled on top of metaphor, I just couldn’t come up with a simple explanation.

A much clearer metaphor came to me today, so here goes:

I ask Charile to drive to the store. 
At the same time I ask Sally to go along and pick up something from the store. 

And just like that we’ve created a race condition. Sally getting to the store depends on her riding with Charile. I never told Charile to wait on Sally, so Charile gets in his car and drives away, leaving Sally stuck with no way to complete her task. 

Now Charile is usually slow getting ready, and thus slow to get to his car. This means Sally is usually there waiting on him. But every now and then, Charile has is keys in hand, ready and waiting.

So often Sally will make it to the store, but every so often she won’t and the system falls apart.

This is the most basic race condition. Two tasks (one driving, one riding) where one depends on the other, and it can be fixed simply enough. We just need to tell Charile to wait until Sally is ready, and then drive to the store.

I’d be interested to hear other people’s non-CS explanations for problems like race conditions, deadlocks, memory management, etc.

California Living

13 Dec

You might have noticed I’ve been very quite for the past couple of months. That’s because I was / am going through a major change in my life.

In October I accepted an exciting offer to work at my favorite fruit tech company out in California. This has been the biggest change to my life since joining the Air Force in 2001. It’s entailed moving to California; Being separated (physically) from my wife as we work out the logistics of her job / move; Selling our home and finding an apartment (insert Bay area housing cost rant here); Resigning from my full time position in the Air Force and transitioning to the CA Air National Guard as a weekend warrior; Not to mention meeting all new co-workers, making new friends and trying to contribute as best I can in my new software engineering role.

It likely goes without saying that the first month or so was incredibly stressful. Luckily I have a fantastic boss and incredible co-workers that have been very welcoming and helpful. In fact, the personal connection I felt to them, as well as their respect for each other and family is largely what made up my mind to take the this leap in the first place.

Software engineering can often be a solitary activity, but to me its best when it’s a social activity. I do my best work when I can quickly, and freely, bounce my ideas off of others without fear of negative feedback or harsh judgments. No one has all the answers, and often we can get laser focused on one solution, sometimes to the point of gridlock. Having an environment that promotes open discussion is key to getting the best work and better moral.

My lack of any CS or CE degree has often made me feel inferior to other developers. I know there is value there that I’m missing. Not necessarily in the degree itself, but in the experience I would gain and the skills I would develop if I had gone down that path. While I lack the academic experience, I’ve got years of practical experience instead. There is value in both, and I’m slowly realizing that. My biggest hurdle so far, with the lack of academic experience, boils down to vocabulary. There are terms and descriptions that I’m simply not familiar with. Once explained the concept I can understand; but it slows me down and leaves me lagging in some conversations. I’m confident I can pick up these missing bits over time, and I’m as certain as ever that there is a world of knowledge out there for me to learn beyond that.

All this has left me with very little time to blog; Though, I’ll still try to post from time to time when I think I have something worth saying.

That’s it for now, I’ll be back as soon as there’s something interesting to say.

Saving structs with NSValue

3 Aug

Janie details her efforts persisting data to disk.

Something crept into my mind while reading her post; this seems like a case that NSValue could address well.

NSCoding and NSDictionary are good ways to persist values to disk. But if you have a small struct that you don’t expect to change the definition of, NSValue might be the right tool for the job. NSValue conforms to NSCoding, or, more precisely, NSSecureCoding. That means you can use NSKeyedArchiver to save any NSValue to disk however you like.

NSValue has some nice connivence methods that allow you to easily deal with rects, sizes, and points. To get a value representing a rect that you can save to disk is just one line:

NSValue *aValue = [NSValue valueWithRect:someRect];

This is handy, but NSValue‘s real power starts to show when we look at [NSValue valueWithBytes:objCType:]. Don’t let the objCType name fool you, this method works with C types too. With this method we can convert C types, like structs, to NSValue objects for easy archiving.

Armed with this knowledge, lets see how we might use NSValue to address Janie’s coordinate issue.

typedef struct {
    double x;
    double y;
    double z;
} Coordinate;

@implementation NSValue (Coordinate)
+ (NSValue *)valueWithCoordinate:(Coordinate)coord {
    return [NSValue valueWithBytes:&coord objCType:@encode(Coordinate)];
}

- (Coordinate)coordinateValue {
    Coordinate coord;
    [self getValue:&coord];
    return coord;
}
@end

That small category allows us to work with Coordinates as NSValues real easily.

Coordinate coord;
coord.x = 1.1;
coord.y = 2.2;
coord.z = 3.3;
NSValue *coordValue = [NSValue valueWithCoordinate:coord];

And to get the Coordinate back out of the value is just one line:

Coordinate coord2 = [coordValue coordinateValue];

That’s all there is to it.

There is one gotcha though. As I said earlier, this is really only a good solution if you’re relatively certain that your struct’s definition won’t change over the life of your app. This is because NSValue doesn’t have any knowledge of the data you save into it. It treats the data as just a blob of bytes. So, if we decided that we really only need x and y so we delete z, we would break our app.

I would argue that a coordinate struct is very unlikely to change, and that if it did change significatly we might be better suited by creating a whole new struct anyway. Say, Coordinate2D vs the original Coordinate struct.

So, if you’re thinking about archiving a struct, consider NSValue, it might be just the tool you’re looking for.

Tagged Pointer NSStrings

31 Jul

Mike Ash’s Friday Q&A this week talks about Tagged Pointers and NSString.

If we’re optimizing for ASCII, we might as well drop full Unicode support altogether. Strings containing non-ASCII characters can use real objects, after all. ASCII is a seven-bit encoding, so what if we allot only 7 bits per character? That lets us store up to eight ASCII characters in the 60 bits available, plus 4 bits left over for the length. This is starting to sound useful. There are probably a lot of strings in an app which are pure ASCII and contain eight characters or fewer.

AutoAssets build script

22 Jul

Working with Xcode image assets in code is pretty easy. Just include the images in a Xcode assets file and throw in some UIImage calls like so:

UIImage(named:"someImage")

Although it’s unlikely to cause any crashers, you can easily end up having a typo somewhere and ship your app with a missing image. Not to mention you have to remember and type out the image name every time you want to use it.

There are better ways of course. For example, you can make it a bit better by using string constants. You’ll end up with something like this:

UIImage(named: LAMSomeImage)

Or you could wrap them in a category

LAMAssets.SomeImage()

But Jesse Squires proposes a better way using enums, which also provides proper name spacing. You should really read his post, it has some great stuff on dealing with colors too.

With Jesse’s method you access the images using the following style

Assets.SomeImage.image()

The difference between his enum style and using a category is subtle in use, but significant in implementation.

Inspired by his post, but not wanting to keep enums up-to-date with my Xcode Assets, I made AutoAssets.

AutoAssets (written in Swift) is a build script that generates a Swift source file at build time based on the projects assets. Basically it takes Jesse’s enum idea and automates it.

Here’s the repo

NSData+Compression and API costs

21 Jul

During my Tinkering with CompressionLib series I built a small NSData extension (or category depending on your language of choice) to make compressing / decompressing data easier.

It had only two public methods:

func compressedDataUsingCompression(compression: Compression) -> NSData?

func uncompressedDataUsingCompression(compression: Compression) -> NSData?

I debated about adding initializers to the extension, but decided to hold off initially until I could give it some more thought.

It sounds trivial, but every bit of public API you expose is that much more you need to support. The cost of adding API isn’t really the code itself. Code is just one part. You have to consider the design, testing, documentation, maintainability, and support costs too.

What finally pushed me over the edge was reviewing NSData’s API.

NSData exposes convenience methods for initializing from the contents of a file

init?(contentsOfFile path: String)

And frequently when you’re dealing with compressed data it’s stored in a file on disk. So it seems only natural that you would expect to be able to both read it in and have it decompressed at the same time. After all, it is pretty unlikely that you’re going to read some compressed data into memory and leave it compressed.

So I added two convenience initializers to my NSData extension today.

convenience init?(contentsOfArchive path: String, usedCompression: Compression?)

Which returns a NSData object initialized by decompressing the data from the file specified by path using the given compression algorithm.

And the shorter “smarter” version

convenience init?(contentsOfArchive path: String)

Which returns a NSData object initialized by decompressing the data from the file specified by path. Attempts to determine the appropriate decompression algorithm using the path’s extension.

This method is equivalent to NSData(contentsOfArchive:usedCompression:) with nil compression

Here’s the repo for the Swift version.

Or, if you prefer, you can grab the Obj-C version here.