The iPad - two ... no, fifteen, weeks in

I've had a draft post in MarsEdit for some time now called "The iPad - two weeks in". Clearly that title is a little outdated now.

What's interesting is that my opinions haven't really changed in that time. So what follows is my unedited thoughts just over four months ago. I'll follow up with what has changed in the meantime - but that is all due to external factors.

The iPad - two weeks in

I've had my iPad now for two whole weeks. I've not used it as heavily as some in that time, but I think it's long enough to give my initial impression. I've publicly been quite excited about the iPad in principle since it was announced - but now I've been able to taste the proof in the pudding.

After the initial opening, where you find out for yourself how natural using apps like Safari and Maps are on the new device there's an inevitable awkward period where you realise that it doesn't do anything (yet) that you couldn't already do with your laptop or your phone. For some people this is all they see. That is, of course, missing the point.

First of all I'm used to taking my laptop with me everywhere - and if I don't have that I still have my iPhone. There are not many occasions where I need more than my iPhone, don't have my laptop but would have my iPad. But that's mostly because I'm a developer. If I wasn't using it for coding then most days I would probably leave my laptop at home and just use the iPad on the train.

In time, however, I've started to reach for the iPad first, even if I have the laptop with me. Why? Well it's smaller for a start. I have a 17" Macbook Pro - which is quite a lot to pull out on the train if I don't really need it. When I'm coding I really appreciate the extra screen estate - but for just about anything else it's not needed.

I'm also finding it generally a nicer, more natural, experience to interact with apps and content through the touch metaphor - especially Apple's implementation. After three years of iPhone O..., I mean iOS I still get great satisfaction in working with the interial scrolling views, for example.

So far this has just been a refinement of an experience I already had - it's not adding anything truly new - and there are some downsides, which I'll come on to. It's worth mentioning here, though, that we're only just getting off the ground with this. I'm very much an early adopter here. It's a little unusual that the hype around the iPhone and iPad have lead to such mass adoption already. There are bound to be people who expected more or are still wondering what you can actually do with these things to make them worth their keep. It will come. It will all come (and, as alluded to in that blog post I linked earlier, I hope to have my own part in that).

So that's the positive and the realistic. What about those negatives that I mentioned.

Well the first is that with the larger display and extra power you really do miss multi-tasking. Of course that's coming soon, to a degree, and that will mitigate most of my concerns here. However I do feel that in some cases it would be nice to have more than one app on screen at a time. I wouldn't want this to be the default way of working - as it is with desktop OSes. But the ability to do this selectively, perhaps with the widget metaphor, would be a nice addition. That said I'm a power user and not everyone would need or be comfortable with this. Even if we never get it, with the service-based multi-tasking that's coming it's going to be a good experience.

On a similar note I'm finding mobile Safari to be much more frustrating than in the iPhone context. Two things - the lack of tabs is annoying. While you have a somewhat similar mechanism in the form of the page toggle view, it's not the same and if you want to do a bit of research it's very limiting. Of course this is entirely a software implementation issue and there's no reason it couldn't be added in a future release (allowing for my next point).

The other issue with Safari, which it also inherits from the iPhone, is that it doesn't seem to do any disk caching. It holds a whole page in memory. If you switch to another page and it runs low on memory it will purge the first from memory and if you then navigate back it has to load the whole page over the air again! I feel this would need to be addressed before tabbed browsing could be offered.

Finally - and I think this is the biggest grievance I have with the iPad today - is the glossy screen. It's fine in low light conditions (if you turn the brightness right down). But outdoors, especially if the sun is out - or even indoors if the lights are bright - the display is really hard to read from and tires the eyes very quickly. What concerns me most is that Apple seem to be fine with this. Their "solution" is just to crank the brightness up until it overcomes the glare. This almost works. Sometimes even that is not enough - and it certainly doesn't address the eye strain issue - tiring them even more.

Before the announcement back in January the display technology was probably the most talked about aspect of the then-rumoured device. From reading the opinions at the time it sounded like if the iPad launched with backlight display at all - let alone a glossy one - it would be an instant failure. After the announcement those opinions became a distant minority as everyone else focused on what's great about the device. Sales so far certainly don't seem to be hindered by this weakness. This is a shame because I think it will just give Apple reason to ignore it altogether. I hope I'm wrong. After all they did do a U-turn over the same issue with the Macbook Pros when they went glossy. I held off getting a new laptop until they finally offered a matt display option again. I'm not so hopeful with the iPad, however since it's the glass that makes it glossy and that really needs to be there on a multi-touch display. The glimmer of hope, no pun intended, comes from the iPhone 4 which apparently pioneers a new manufacturing technique for connecting the LCD to the display which closes the gap between them. I'm hoping this will reduce glare - at least a little - and that this technology will work its way into the next generation of iPad devices.

In summary, there are irritations and weakness but all of these, with the exception of the glossy display, can be fixed with software updates - and I'm confident that some of these will filter through. The display is particularly disappointing but for many people it's fine. It's potentially "fixable" in future hardware revisions. An anti-glare screen protector may help too, although I've been reluctant to try one just yet.

Despite these downsides, and the early stage that the eco-system is at in terms of must-have apps, I still find the iPad to be a really great device that currently has no equal. It's not yet for everybody but I really do believe that the trend is that this gap will close.

The one area that I think the iPad will really shine - and we're only seeing embryonic examples yet - is in note capture and consumption. The immediacy of iOS, the natural interaction of multi-touch and the larger display/ touch surface of the iPad are, I think, the perfect ingredients for making the capture of notes and ideas directly into digital form more practical and accessible than ever before. This is the direction my app ideas lie in and I'm really excited by the possibilities now on offer.

Remember - the revolution is only just starting.


Welcome to the new decade

What makes a tweet take off? I recently had a tweet go viral and it gave me a fascinating insight into the how and why these things spread. In some ways Twitter amplifies existing social epidemiology. In others it is unique.

So what was the tweet? It was a Saturday afternoon - about 4pm here in the UK. I was having a shower (where most of my best ideas are formed) and I was thinking about recent tech news. It struck me that recent events (Oracle suing Google over Java, Google net neutrality controversy with Verizon) have added to other changes (Apple's rise to the top of the mobile, online music and tablet spaces - and even eBooks - and Microsofts inability to get into - or back into - and of these area) has resulted in a reversal of some of the positions we have taken for granted over the last ten years or so.

So, as I was drying off, I posted a casual message on Twitter. I had around 200 followers at the time - at least half of whom I know personally. I thought I might even get a couple of retweets.

The tweet read as follows:

Welcome to the new decade: Java is a restricted platform, Google is evil, Apple is a monopoly and Microsoft are the underdogs

That's 125 characters to summarise the juxtapositions I had been pondering. Like most tweets where several thoughts are being conveyed it took a couple of iterations to prune it enough that it fit into the 140 character limit - and leaving just enough space for the RT.

Just in case.

After that I took my family off to my sister's, where we had been invited for the evening, and didn't think any more of it.

My sister's house is a bit of a 3G (or any G, for that matter) blackspot. If you've seen those adverts for femtocell repeaters that have people hanging out of windows to get a signal then you have an idea of what it's like.

However, even there, my Magical iPhone 4 antenna occasionally picked up a signal and I'd get email in bursts. During the course of our meal I heard a few emails popping in and took a look. My unread emails badge told me I had 50 emails waiting. 50! As it turns out, 50 is the maximum number of email headers the iPhone will download automatically. I don't know how many I already had at that point. But it was a lot.

So what where they? They were notifications from Twitter of new followers.

I managed to get a connection to my brother-in-law's wifi - which has a 128 character hash as a password (!) - and checked in on my twitter account. And there it was. Screen after screen of my tweet retweeted over and over again! A three letter word came to mind. It starts with W and ends with TF!

I couldn't investigate fully until I got home. By that time I found I was #1 in two categories on Reddit - and later found I had also been #1 on Hackernews all night! A little more searching showed the tweeting popping up in other places too, mostly blogs. By monday I heard I'd even had a mention on "This Week in Tech".

By Tuesday (already three whole days later) I was still seeing retweets in my timeline every few minutes, and new followers were trickling through. They seemed to have levelled out at around 900 (some people were already unfollowing) - but then over Tuesday night (UK time - so day/ evening across the US) it picked up again leaving me with 930 by Wednesday morning.

So what happened?

My Twitter Social Ego Networks.jpg

Tipping Point? Or Life Of Brian

If you've not read Malcolm Gladwell's Tipping Point you're probably at least familiar with the phrase, or can take a guess at what it means. It's all about the factors that contribute to the adoption or awareness of something taking off - usually by several orders of magnitude. Almost by definition this is not an exact science. If you want to paint a scientific face on it I'd probably paint it with Chaos Theory. In practice the elements that Gladwell covers tend to be more sociological, and usually highly anecdotal.

But a tipping point seems to have been what was reached here - so what does Gladwell have to say about the process?

Connectors, Mavens and Salesmen

Probably the most obvious example of a Tipping Point factor are Gladwell's: "Connectors". These are people who have a lot of social connections. They know people. (Even more) people know them and generally trust their opinions. Often these people will be celebrities or with some other form of media presence. Book authors, tech journalists or high profile employees of big name companies are common Connectors in the tech world. There were certainly a number of these in the mix and they would have played a huge amplifying role in the process. I can't imagine my tweet would have "tipped" without them. Some of the names I've seen are: Robert Scoble, Leo Laporte (who had mentioned me on TWiT and Travis Swicegood (author of "Pragmatic Version Control With GIT", and who posted the tweet to Hackernews). With a bit more digging I'm sure I'll turn up more, perhaps even bigger names.

Gladwell also talks about Mavens and Salesmen. In this case I believe the Mavens involved where probably also the Connectors. Salesmen have less of a role in a Twitter epidemic.

Stickiness and tl;dr

Gladwell's concept of the "Stickiness Factor", I believe, translates to the quality of the tweet that led it to take off in the first place. After all it needed enough momentum to reach the connectors.

In retrospect I can have a good stab at what it was about the tweet that gave it Stickiness. I want to emphasise that I can't claim credit for how effective it turned out to be. That was mostly down to luck and the constraints imposed by Twitter itself.

Twitter's famous 140 character limit, while it has other historical reasons, has proved to be one of its most compelling (and sometimes frustrating) "features". It's an oasis in today's crisis of information overload. Anything else is tl;dr.

And yet at the same time we are addicted to content - especially social content. We want more of it, but in smaller amounts. And that's precisely what Twitter gives us. Furthermore we are forced to think about how we can keep within that limit - compressing paragraphs of material into a couple of laser focused sentences. We often surprise ourselves at how much unnecessary waffle we can distill down to essence of the point we wanted to make.

And that's exactly the process I went through to arrive at the wording in my tweet.

But it wasn't just the fat that was trimmed. There was no room to explain the nuances, resolve the ambiguities, or balance the controversy. Twitter editing is brutal. It has to be left to the reader to add the flesh back to the bone.

Anyone familiar with recent events in the tech world could identify with the sequence of statements - whether they agreed with them or not. But each person also read into them their own interpretation. Some took exception to what they thought I was implying. This was important. If you look at the discussion threads that exploded on Reddit and Hackernews you'll see how many possible interpretations and opinions about each word were represented.

It's a sad, but well known, fact that controversy "sells". Each point I made had enough truth that it could be talked about in serious debate, but was controversial enough that people wanted to do so. The fact that each point was also a reversal of a previous view was the light and amusing packaging for this combustible concoction. Top that off with the easy to read meter, practically forced on it by the Twitter limit and it's hard to imagine a more carefully planned Stickiness assault on the Twitterverse.

Yet it really wasn't planned that way.

Anatomy of a perfect tweet

We've looked at the general Gladwell effects that probably contributed to the tweet "tipping". Considerable research has also gone into to more specialised effects within the context of retweeting. What makes the difference between something being retweeted 0-5 times compared to something that takes off to hundreds, thousands, or more?

Perhaps the most notable Social Media expert in this area is Dan Zarrella. He has broken down vast numbers of statistics and correlations and come up with some key observations. These include things such as the type of words that are most retweetable, sentence structure, time of day, day of week, and many more. Some of the effects are more pronounced than others.

Looking at the timing: Dan suggests the best time of day to be retweeted is sometime in the early evening. According to his graph this peaks about 5pm. Sure enough that was almost exactly the time I posted. So that goes to prove the point? Well it would be a mistake to look at a sample size of one and draw conclusions. There are also problems with this statistic. Twitter is a global phenomenon. Most people have at least some international members of their network. So time-of-day is all but meaningless. In my case, being based in the UK, I think 5pm worked out well because the U.S. was coming online and spread throughout the day.

On the flip side, the best day of the week is apparently Thursday. The worst day of the week is Saturday! As I said these are statistical biases - not absolutes. Nonetheless his findings are very interesting and can make you rethink the quality of your tweets.

I was a little surprised that he didn't even mention, at least in the linked article, network effects of the Tipping Point variety (although arguably most of his findings relate to the Stickiness of the content).

A numbers game

As this saga unraveled I became more and more fascinated with it. I wanted to see how many times it had been retweeted, by whom, seen by how many, and who the Connectors were. There are tools online to help, but they are constrained by Twitter limits (for example only the last 1500 tweets from a search). To get around this I made multiple searches using the since: and until: commands. Unfortunately these only work for dates - not times. On Sunday I had more than 1500 retweets in the final eight hours alone!

So I wasn't able to piece together the whole story, but by throwing in a few estimates for the missing data I arrived at a figure of about 3-4 million impressions (that is, people who would have seen the tweet, given the followers of those that retweeted - allowing for overlaps).

I think the first big Connector in the mix was Robert Scoble, about 3 hours and 30 retweets in. During the rest of saturday evening it was picked up by five others with more than 10k followers each - including @toptweets with 354k followers alone! I suspect Sunday had the most Connectors at play. Unfortunately most of Sunday is a bit of a black hole due to those Twitter limits.


Blessed are the cheesemakers

At times it seemed like I'd got trapped in Life Of Brian - only with less Romans. When anything plays out on a large enough social network; the thing itself takes on a life of its own - detached from its origins. This was Dawkins' memetics at play in a highly concentrated form. But being so accelerated, even a network as large as Twitter reaches saturation fairly quickly. I was amazed that by Wednesday I was still being retweeted so much, but by Friday it was finally abating - with only about 3-4 retweets an hour.

By next week it will have gone the way of the dinosaurs. My days as a micro-celebrity are numbered.


OCPtr - a Smart Pointer for Objective C

In my last post I covered why we might want Garbage Collection on the iPhone, some reasons why we don't have it, and how the same problem is solved in C++. I then hinted that we might be able to bring the same C++ goodness to Objective-C - if we allow ourselves to use Objective-C++.

In this post I'm going to introduce my own solution.

Say hello to OCPtr

Rather than dive into the implementation, let's look at usage - and how it addresses our memory management needs. Let's start with our first example - allocating an NSString. Here's how it looks using OCPtr:

OCPtr<NSString> str = [[NSString alloc] initWithFormat: @"One: %d", 1];

// ...

The first thing to notice here is that instead of declaring our type as NSString* we declare it as OCPtr<NSString>. This is how smart pointers work. C++'s power is with types - especially when mixed with templates. OCPtr<NSString> is a complete type. Furthermore it is a value type. At the end of the scope it will be destroyed. In its destructor we call release on its NSString* member - which brings us to the second thing to notice - we have omitted the [str release] step!

Let's think about that for a moment. On the face of it we have saved ourselves 14 characters - but at the cost of six characters in the declaration - a net saving of eight characters. Woohoo! Obviously if this was all there was to it I wouldn't be writing this blog post. I'm not that obsessed with removing redundancy!

What is more significant is the reduction in the mental overhead of tracking when you need to call release - and the debugging overhead when it goes wrong - not to mention the potential for financial overhead if it only goes wrong when your users are using it.

In this simple example it doesn't seem to have given us much - but think about this again next time you're trying to track down a particularly elusive leak or over-release.

Of course real code is more complex than this, and OCPtr will need to be more than this to function as a stand-in for raw pointers. Years of C++ smart pointer experience tells us we need to overload the assignment operator, provide copy constructors (allowing us to create one OCPtr from another), and ideally overload a few other operators too. Technically a true smart pointer would overload the -> and & operators to behave like raw pointers - but these are not used with Objective-C types, so I haven't provided them. Other than that OCPtr provides all of this, so simple assignments result in retain counts being updated appropriately, and objects are released as their OCPtr wrappers leave the scope.

Some smart pointers also overload the conversion operator (this is invoked when you try to cast an object - whether explicitly or implicitly) to convert to the underlying raw point. This is a controversial practice, and can lead to ambiguities. However in the constrained environment of Objective-C code it seems safe enough - and gives us one key advantage: it allows us to send messages to the underlying object without additional syntax. Here's some more code illustrating this as well as some of the other preceding points:

  OCPtr<NSString> str = [[NSString alloc] initWithFormat: @"One: %d", 1];

  OCPtr<NSString> str2;
    OCPtr<NSString> str3 = str; // retain count == 2
    str2 = str3; // retain count == 3

  } // retain count == 2

  // ...

} // retain count == 0 - dealloc called

Not just Smart - it smells nice too

So what else can we do with OCPtr?

Well it wouldn't be so useful if it couldn't also manage instance variables. OCPtr does that too - as long as you have the project setting enabled for: "Call C++ Default Ctors/Dtors in Objective-C". This setting seems to be enabled by default now, but it's worth checking. Now if all your ivars are held as OCPtrs you don't even need to write a dealloc method. The compiler will effectively write it for you - and all your OCPtr destructors will be called - releasing all their managed objects.

What about properties?

To some extent there is an overlap between the functionality of synthesised properties and what we are doing here. That is, if you declare a property for an Objective-C object with the 'retain' attribute then the synthesised code will include the retain-release code necessary to do the right thing. This does relieve the programmer of some work - so is OCPtr buying us anything?

Well, using properties still places two responsibilities on the caller: First they must remember to use the property syntax (whether the dot-syntax or the direct messaging passing) everywhere (including within the implementing class - except at the point of allocation). Secondly they must still remember to set the properties to nil in dealloc - which is really no improvement over just releasing them.

So retain properties do help with change of ownership - but at the cost of having two ways to do so - one which is automatic - the other still manual.

But can we declare properties for OCPtr ivars - and what happens with the retain counts?

Well recall that you can write a property for any Objective-C type - which includes all C types - primitives and structs. In the latter case you will use the assign attribute instead of retain (and assign is the default - so even easier). In this case no retain-release code will be generated - values will just be assigned directly. But OCPtr overloads assignment to provide retained change of ownership semantics. This gives us exactly what we want!

@property OCPtr<NSString> str;

So, in short, use assign properties to provide external access to OCPtr ivars. Internally you can use either form of access but they work the same way. In either case assignment works as it should and references will be cleaned up in dealloc. This is surely an improvement.

Transfer of ownership

How does OCPtr work with autoreleased objects? If you initialise an OCPtr with an autoreleased object you do still have to tell it to take ownership. This is no different to a raw Objective-C pointer. In both cases to take ownership you must call retain. E.g:

OCPtr<NSString> str = [[NSString stringWithFormat: @"One: %d", 1] retain];

It niggles me a bit that we still have to make a distinction between autoreleased and non-autoreleased objects - but that's a property of the autorelease mechanism itself, rather than a limitation of OCPtr (I could imagine a scheme where OCPtr detected that the pointer being passed was in the autorelease pool - but there would be no way to know for sure if that related to this assignment - and would probably be taking things to far anyway).

But take a step back for a moment. What is the problem that autorelease solves in the first place? autorelease's raison d'être is to provide transfer of ownership semantics. If a method creates an object but does not own it (typically a factory method) - it just returns it. In order to return it with a valid retain count, without requiring that the caller release it, it adds it to the autorelease pool to be released some time later. This works, but adds extra rules and syntax, and can result in objects living longer than they need to.

But smart pointers already solve this problem. By returning an OCPtr, the retain count will remain valid until after the assignment operator of the caller's OCPtr has retained it. The returned OCPtr then immediately goes out of scope (it is a temporary object). The net result is that you can freely create and return OCPtrs just as you can primitive types - no need to worry about retain counts or autorelease pools.

-(OCPtr<NSString>) someMethod
    OCPtr str = [[NSString alloc] initWithFormat: @"created here"];
    return str;

} // str will be released here but caller already has it

// ...

-(void) someOtherMethod
    OCPtr<NSString> str = [self someMethod];

} // str will be released here, retain will go to 0 and dealloc called

Of course if you're working with third-party APIs (including the SDK frameworks) you will still need to work with autoreleased objects at times, so it's worth remembering that you still need to retain them before putting them in an OCPtr.

But wait - there's more

What we have discussed so far covers our memory management needs. But if we've accepted a general purpose object wrapper into our code we have opportunity for further, aspect-oriented, benefits:

id type checking

One of the great things about Objective-C is that it is a dynamic language (albeit with static underpinnings).

One of the biggest problems with Objective-C is that it is a dynamic language (fortunately with static underpinnings).

While it is nice that we can choose to use typed, untyped (id) or partially typed (NSObject) objects, sometimes we are forced to go untyped when we'd like the benefit of type checking. The consequences of getting the types wrong are usually crashes, with not so helpful error messages - and at a different point in the code. We can check types at runtime, of course, with the isKindOfClass: method, to which you have to pass a class object - obtained by passing the class message. This can clutter the code up with mechanics.

OCPtr provides a conversion constructor from both id and NSObject, which will test the types (using the class and isKindOfClass: methods) before casting internally. As a result if we do this:

OCPtr<NSArray> str = [[NSString alloc] initWithFormat: @"hello"];

... we will get an exception that tells us exactly what happened.

If we had used a raw NSArray* pointer here the assignment would have worked - but we'd get errors further down the line if we tried to call array methods on it. These can be difficult to track down.

Don't want to pay for the check? Just cast to the target type before you assign (but lose the benefit of the type checking - so the principle is "correct by default, fast where necessary").

Release early

By eliminating your memory management bugs you will be able to release your apps earlier - but actually I was referring to releasing objects early.

Sometimes you're done with an object in the middle of a scope and you want to release it there and then. If you do this you are strongly advised to then set it to nil - to avoid the chance of anyone trying to use no longer valid memory. With an OCPtr you need only set it to nil and you get both advantages. You've been able to do this for a while with properties, but now you can do it directly with ivars, and even with local variables:

	OCPtr<NSString> str = [[NSString alloc] initWithFormat: @"One: %d", 1];

	// ...

	str = nil; // release is called here, and the underlying pointer set to nil

	// ...

Logging hooks

A powerful, but easily abused, feature of C++ templates is a concept known as specialisation (unfortunately a rather overloaded term in OO languages). A template is specialised when you write specific code for the case where a template's type argument(s) are of specific types. If that doesn't make things any clearer I'll explain how this relates to OCPtr and logging and hopefully it will click.

OCPtr comes with another template class: OCPtrHooks. OCPtrHooks declares a set of empty methods and nothing else. Each method represents a state change in OCPtr (e.g. onAssign) and OCPtr uses an OCPtrHooks class, parameterised with the same Objective-C type, calling the appropriate hook method as things happen. Because all the methods are empty the compiler is able to optimise these calls away completely.

So if the methods do nothing and they are not even compiled in what use is this? Well, due to the magic of template specialisation we can write a version of OCPtrHooks specialised for a particular type - or even partially specialised for a base type. Then, for those specialised types only, your custom versions will be called.

You can implement your specialisations to do anything - but a useful implementation for us is to log the events. Enabling logging for a particular type is as easy as declaring a specialisation that derives from a logging base class, like this:

template<> class OCPtrHooks<NSString> : public OCPtrLogHooks{};

Don't worry about trying to follow that if you're not a C++ programmer. The important bits are the template type parameter (NSString, here) and the base class (OCPtrLogHooks). Just substitute the NSString for any type you want to log and it will start working - with no overhead (not even an if) in all other cases.

While this is powerful, and useful, it does make use of, and expose, some tricky template syntax - If you're not already familiar enough with C++ to know how this works you may choose not to take advantage of this facility (I might try and make it friendlier in the future - even if that involves the use of a wrapper macro).

The dark side

So we've eliminated the mental overhead of manual retain counts, without introducing any runtime overhead, added transparent runtime type checking to dynamic types, along with several other benefits. With all this goodness everyone will want to use OCPtr, right? They'd be mad not to?

Well, that's generally true of C++ smart pointers in the C++ world. But because we're intruding the world of C++ into the world of Objective-C, and using a hybrid language to do so, there are some drawbacks to consider. These are the ones I think are relevant:

  1. OCPtr is a C++ template. This means it must be #included or #imported - so all your implementation files will need to be .mm files (or you can set the filetype in the file info dialog).
  2. C++ syntax intrudes into your application code in the form of the OCPtr<MyClass> syntax.
  3. The idea of custom value types may be unfamiliar to people reading the code. The fact that assignments handle retain counts for you may be a surprise, for example.
  4. If you use an OCPtr in an untyped context, e.g. as an argument to NSLog, the compiler cannot deduce that it needs to return the raw pointer out. So you'll need to explicitly access it - either calling a C++ method, such as get(), or casting to the underlying type.

Issues 1 & 2 are the most likely to put someone off - and they become especially significant if you are writing code for a client, or as part of a team in a larger company - especially if you are not already using any Objective-C++ on the project.

So I wouldn't necessarily recommend that everyone just start using OCPtr everywhere - but if you are just writing for yourself - or as a small, open-minded, team - I'd encourage you to at least give it a try and see if it can make your life easier.

But at the end of the day, even if you decide the trade-offs are not worth it for you, you can at least rest easy knowing that manual referencing counting is a choice. And you can tell all your gloating friends who use other languages, "I don't need no stinking garbage collection!"

Give me the codez

So where can you get OCPtr. I'll shortly be putting it up on GitHub. When I do so I'll update here with a link.


We Don't Need No Stinking Garbage Collection

iPhone developers are sometimes called names or excluded from polite circles for not having Garbage Collection. Recently I gave a presentation at the London iPhone Developers Group meeting which covered this matter from a few angles - including some techniques of my own. There was enough interest that I thought I should write it up in a more widely distributed format - where I could also expand on some points I glossed over due to time constraints (it was 20 minute slot).

Koviks avfallsdeponi.jpg

What's that Smell?

So what's the stink about? Well, if you develop for the iPhone you're going to have to use Objective-C (at least for some of your code - e.g. the UI). Until recently Objective-C has not had any form of Garbage Collection. Memory must be managed manually (although helped by a reference counting system). As of Objective-C 2.0 there is now a GC facility but this is only available on Mac OSX - from Snow Leopard on.

Most languages in common use today have Garbage Collection. There are three stand-out exceptions: Objective-C (on the iPhone), C and C++. As it happens this is precisely the same trio that are sanctified for use on the iPhone (I'm deliberately avoiding the issue of front-end languages/ platforms such as Monotouch - especially while their status with respect to the developer licence remains in doubt)!

So why no GC on the iPhone? Before we look at that I think it's worth a quick review of why anyone would think it was needed in the first place.

Remembering to forget your memory usage

Consider this typical snippet of Objective-C code:

NSString* str = [[NSString alloc] initWithFormat: @"One: %d", 1];

// ...

[str release];

The use of NSString here is not that interesting. What we're looking at is that, because we used alloc to get the string we need to remember to call release when we're done. Note that release doesn't necessarily deallocate the memory for the string there and then. The Objective-C runtime uses a reference counting (or retain counting, in Obj-C parlance) system to track when the last reference is released - at which point dealloc will be called - giving the object a chance to clean up its own resources.

This is hardly rocket science, and already has many advantages over the raw C way of doing things where ownership can be passed around like a hot potato and often it is difficult to know if you should be responsible for freeing or not (yes - conventions exist to mitigate this - but they are not standardised).

But when you start putting stretches of code in the middle, maybe with multiple exit points (unless you're a SESE fanatic - and eschew exceptions) it already starts to add mental overhead. Not much, maybe, especially to an experienced developer - but spread across thousands of instances it adds up. When you're writing code you want to focus as much as possible close to the domain level of abstraction - and these language mechanics issues can detract from that.

As well as the pattern shown in the example above there are other variations to consider. If the object is an instance variable you have to put the release in the dealloc method (or set it to nil via a property if you prefer). If the object is obtained from a static convenience constructor (such as [NSString stringWithFormat:]), or if you send it the autorelease message, then you should not call release yourself - but you do need to be aware the the object will live beyond its last use - which may be significant.

If you are given an object, but not passed ownership, and need to keep hold of it then you will need to send it the retain message (then later remember to call release again).

Whichever case it may be, doing it wrong has consequences. Failing to call release will result in leaks (which may lead to a crash - but much later). Failing to call retain could mean that you are using an object that may have been deallocated. This will likely lead to a crash sooner. If you're really lucky it will crash close enough to the source of the problem to help you find it - unless your users find it first.

Leaks and crashes are serious problems. Even if 99% of your code is correct in its memory management, just one or two such bugs can ruin your user experience (not to mention your app store ratings).


There are some tools that can help. For leaks we now have the LLVM static analyser integrated with XCode. This will work with the compiler to analyse your code paths, looking for misplaced releases or retains. It does a pretty good job and I highly recommend using it regularly. But its not perfect. It misses quite a few cases - especially if the code paths get complex. It can also give false negatives.

At runtime we can also use the Leaks instrument, which will track your references and see when objects are still alive after their last use. I suspect that internally it implements garbage collection, or something like it, to do the reference tracking. Instruments itself has got very good lately - making it much easier to filter out all the noise and see just your bits of the code. Again I highly recommend using this tool. But again it won't catch everything. In particular it will only test the code paths you use while its running.

For over releases, or releasing too early, we can check stack dumps. This may help us to track down the source of a crash - if it's not too far from the suspect code. A better tool, though, is NSZombies - enabled with the NSZombiesEnabled environment variable. With this in operation objects that would normally be dealloc'ed get transmuted into zombie objects instead. These will detect if you send any messages to them and log the fact. There are also a handful of other tools and techniques for tracking down leaks and over releases after the event.

So we can cover up the smell to some extent - but just as with real smells, masking is not the same as removing. We have additional mental overhead distracting you from your task - and extra tools and techniques required to apply after the event.

That's rubbish

So why is Garbage Collection not provided for iOS, given that it's been available on the Mac for about three years?

The short answer is: performance. The slightly longer answer is that GC has an overhead. It's an overhead that you pay every time you run your app. Much of the time the overhead may be invisible, or at least barely noticeable. Sometimes, though, it becomes very noticeable. Common tasks such as scrolling through long lists are famously smooth user experiences on iOS devices. Not so on other platforms, which can tend to be glitchy and jerky.

While bad code is something that can plague any platform (and there are other factors, such as hardware acceleration)- at least it is something you control. Issues caused by GC, though, are outside your immediate control. Depending on the GC implementation you may have access to an API that allows you some degree of control - but this is usually in the form of hints.

Whether you are willing to pay the cost or not, whether you think it's an issue or not, others clearly do have issues with it (and they may be your users). So Apple, as platform provider, has taken the design decision to hold back on providing garbage collection.

This leaves us with managing memory in our own apps. Notice I didn't say "manually managing memory" there. Any good developer - faced with implementing the same patterns of code over and over - even small snippets of code - but especially where missing them is easy and dangerous - find ways to factor out the duplication.

This is a problem that was solved years ago in C++, employing a concept known as RAII.

RAII of light

What is RAII, and how can it help us in Objective-C?

RAII stands for Resource Acquisition Is Initialisation - which is a long and complicated sounding name for a simple but powerful concept. It's also an unfortunate name as it sounds like the focus is on "acquisition" and "initialisation", yet the most interesting part is at the end of the lifetime. To explain what I mean let me cast it in Objective-C terms (if you're familiar with C++ and this concept feel free to skip ahead):

An Objective-C class has one or more initialisers, and a dealloc method. We use these methods to manage our resources (usually pointers to other objects).

In our init method (or designated initialiser) we typically either allocate other objects, or retain objects passed in. Either way we own references to them that we must release later, in our dealloc method.

Of course, we never call dealloc directly - it is called by release once the last retain count has gone.

In C++ the equivalent of init methods are called constructors and the analog to dealloc is the destructor. Where C++ differs is that instead of all objects being reference counted heap objects we have either plain heap objects or value types (which typically live on the stack or, if they are member (instance) variables they are scoped by the lifetime of the object they are a member of).

The nice thing about value types is that they are destroyed immediately, and predictably, at the end of their scope. This feature is so important it has its own name: Deterministic Destruction.

	MyClass myObject;

	// ...

} // destructor will be called here

Now because the the destructor is called automatically at the end of the scope - regardless of how it leaves that scope (so it allows for early returns or exceptions), and we can write arbitrary code in the destructor, this gives us a hook. We can use this mechanism to write code that will be be called as the execution leaves a scope. In fact this technique, along with templates and a bit of operator overloading, has been used for years to implement wrapper classes for raw C++ pointers that look and feel like pointers but have some sort of automatic memory management mixed in. These classes are known, collectively, as smart pointers. Reference counting smart pointers are just one possibility but there are many smart pointer traits that can be captured this way - such is the flexibility (and complexity) of C++.

This is all well and good - but we don't have custom value types, templates or operator overloading in Objective-C. So what use has this discussion been?

Objective C++

Apple's officially sanctioned languages for iPhone development are Objective-C, C and C++. But actually there is a fourth language, not listed there because it's a hybrid. That "language" is Objective-C++. I use the word language lightly here because Objective-C++ is a more of a glue language than a language you would use in its own right. Typically it is used to bridge the worlds between pure Objective-C and pure C++ in order to keep them at arms length (pun intended) from each other.

But there is no technical reason that you couldn't write an entire application, top-to-bottom, in Objective-C++. The reason you wouldn't typically do so is that they have very different syntaxes, strengths and weaknesses, and design trade-offs. Mixing the two just doesn't look like code written in a single language. C++ is oil to Objective-C's water (and we'll resist the temptation to point out how big the leaks can get if you mix oil and water!).

We're going carve out a new niche here. We're not going to freely mix the languages without constraint. But we're not going to keep them siloed either. Instead we're going to use some judicious helpers from the C++ side to assist our otherwise pure Objective-C. I don't suggest this lightly. There are certainly some that would take issue with this approach. We'll discuss these trade-offs later.

In the follow-on article I'm going to put this all together and show you my Objective-C++ solution: OCPtr.


The Ultimate C++ Unit Test Framework

Last night I saw Kevlin Henney's ACCU London presentation on Rethinking Unit Testing In C++. I had been looking forward to this talk for a while as I had started working on my own C++ unit test framework. I had not been satisfied with any of the other frameworks I found, so decided to write my own. I had a few guiding principles that I felt I had come through on:

  1. I wanted to capture more information than usual. I felt I could capture the expression under test, as written, as well as the important values (that is the values on the LHS and RHS of binary expressions, or just the value for unary expressions).
  2. I wanted the test expressions to be natural C++ syntax. That is I wanted comparisons to use operators such as ==, instead of a macro like ASSERT_EQUALS.
  3. I wanted automatic test registration and descriptive test names. Tests should be implementable as functions or methods.

I called my framework YACUTS (Yet Another C++ Unit Test System) and a typical test looks something like:

YACUTS_FUNCTION( testThatSomethingDoesSomethingElse )
	MyClass myObj;

	ASSERT_THAT( myObj.someValue() ) == CAP( 7 );
	ASSERT_THAT( myObj.someOtherValue() ) == CAP( myObj.someValue() + 3 );

If someValue() returned 7 and someOtherValue() returned 11 I'd get a result like:

testThatSomethingDoesSomethingElse failed in expression myObj.someOtherValue() == ( myObj.someValue() + 3 ).
myObj.someOtherValue() = 11, but ( myObj.someValue() + 3 ) = 10

Which I thought was pretty good. I didn't really like the way the expression had to be broken up between the two macros, but thought it a reasonable price to pay for such an unprecedented level of expressiveness. I did think about whether expression templates could help - but didn't see a way around it.

So I sat up straight when Kevlin showed how he'd achieved the same goals with something like the following:

SPECIFICATION( something_that_does_something )
	MyClass myObj;

	PROPOSITION( "values are 7 and 7+3" )
		IS_TRUE( myObj.someValue() == 7 );
		IS_TRUE( myObj.someOtherValue() == myObj.someValue() + 3 );

What I'm focusing on here is how he pulled off his IS_TRUE macro. You pass it a complete expression and it decomposes it such that you get the values of LHS and RHS, the original expression as a string, and the evaluated result - but without any additional syntax!

The details of how he achieved this are too much to go into here - and I don't remember them sufficiently to do a good job anyway. But the core trick he used to be able to "grab the first value" as he put it (and from there it's just a case of overloading operators to get those and the RHS) was to create a capturing mechanism involving the ->* operator. The reason this is significant is twofold: (1) ->* happens to have the highest precedence of the (overloadable) operators and (2) nobody else uses it (well, almost). As a result it can introduce an expression that captures everything up to the next operator (at the same level).

There is more going on here too, which is interesting. Kevlin spent most of his talk building up to the idea of "test cases" being "propositions" in a "specification". The end result is something that grammatically encourages a more declarative, specification driven, flow of assertions. His mechanism also allows him to use strings as test names (or proposition names) and to declare specification scoped variables without the need to setup a class (a specification is really a function). As well as the slight shift in emphasis it also drops a small amount of ceremony, and so is a welcome technique.

Interestingly, although I hadn't fully implemented it, I had experimented with using strings as test names too, even though my unit of test case is still the function. My mechanism was to completely generate and hide the function name, but use the string to pass to the auto registration function. However to reuse state between tests I still had to declare a class (although tests could be functions or methods), so Kevlin's approach is still an improvement here.

What interested me most was perhaps not what Kevlin did that I couldn't (although that is very interesting). But rather how remarkably similar the rest of the code looked to mine! I know that Sam Saariste has also worked on similar ideas - and Jon Jagger was having some thoughts in the same direction (although not as far I think). It seems we were all converging on not just the same goals but, to a large extent, the same implementation! Given that we were already off the beaten track that reassures me that there is a naturalness to this progression that transcends our own efforts.

Having said all that I think I prefer my name, "Yacuts" over Kevlin's LHR (for London Heathrow, the environs of which most of his work was conceived) :-)

I have since fleshed out my framework - now called CATCH - and posted an entry on it.

Page 1 ... 3 4 5 6 7 ... 9 Next 5 Entries »