ARC obliterated entire classes of bugs by automating memory management in acyclic contexts and providing zeroing weak references. Thanks to this, many classes no longer need to perform any cleanup during object destruction. The most common reason for dealloc these days? Notifications.

Broadcast messaging is vital to today's applications, but NSNotificationCenter has resisted modernization. Among its modern failings, its API enables fragile usage and it stores unsafe references to observers.

Karl and I were discussing the error-prone nature of APIs that require bracketed calls, like mutexes that conform to NSLocking1 and addObserver:selector:name:object:/removeObserver:name:object:. He posed the question: how do we get rid of bracketing APIs? To start with, how can we make NSNotificationCenter support weak observers?


1 Less error-prone approaches for mutexes include @synchronized and the modern APIs that take blocks

It's been a while since a photo post from our Europe trip, and the Derry portion would be best shared with a story. Especially like it because it illustrates how we travel. Not in vacation, but in life.

We arrived in Derry by bus, and made our way to the hostel to drop off our backpacks before exploring. An old city by anyone's standards, Derry was a focal point for The Troubles, during which time the original city walls were augmented with solid metal and chain link spans to keep the nationalists and the unionists apart, with checkpoints at the openings. If you're paying attention to your surroundings, it's an unsettling place. The banners celebrating the "City of Culture's" upcoming events struck me as an intentional distraction to attract tourism, a veneer over a far more interesting place.

While walking around the old walls that encircle the old city, we came across some youths that were burning a car. A fire truck had responded, and they'd forced it to turn back with thrown rocks. One of them threw a bicycle through the windshield, pulling it out soon after but not before the grease in the bearings had ignited. The others were kicking at the doors and body panels, jumping on the horizontal surfaces, and generally enjoying the destruction. I was carrying a 50 at the time, so I had to go down the hill and get a closer look. I made myself obvious before shooting, and they took the opportunity to cover up their faces.

Shortly after taking that photo my camera and I almost got taken out by a kid armed with a stick, and that emboldened the rest of them. I got out of there as calmly as possible to avoid inciting a chase as they yelled and threw rocks at me. Back at the top of the wall, one of the locals introduced himself to us, having decided from his vantage point that we were his kind of crazy. He worked as a community youth organizer—he recognized some of the kids from his program—with the goal of peacefully bridging the boundaries in the city. Basically, reducing the incidence of this kind of stuff. We got a walking tour from him that easily beat the other walking tours of the city.

Night fell, we ate and returned to the hostel to sleep. Morning came, and we descended the stairs to the lounge to discover that it had been ransacked. The hostel had been burgled and all of the electronics stolen, including the phone I'd hidden behind the computer to charge. Everyone was a bit off-balance, and we got to talking about our experiences the day before. Someone recommended a pub for us to visit. We noted it, and walked to the police station to file a report first.

We went to the police station to file a report and it was one of the oddest complexes I've ever visited, a modern fortress. If you arrived by car, you were allowed through an armoured blast door and wedge barrier into an enclosed space with another armoured blast door, which you weren't allowed through until the police were sure the vehicle was safe. The history of the Irish car bomb suddenly felt viscerally familiar. Walk-ups were subject to slightly more relaxed security, though I noticed that there was always a minimum of bulletproof glass between us and the officers on duty. We filed an unremarkable report that would never help us get any closer to our stuff.

The pub that we'd been directed to was fairly deep in a nationalist area of the city, and it fell silent the moment we entered. The bar was dark wood, the wall behind it mirrored, and the barkeep and clientele decidedly Irish. A massive flag of Ireland hung on the wall opposite the bar. There were two free stools, so we sidled up and ordered pints of Guinness and Smithwick's. The man sitting next to me broke the silence once we'd had a sip, and asked where we were from. Cognizant of our experiences over the last 24 hours I said, "I'm Canadian," to which he immediately replied, "oh, happy day!" and everyone in the pub fell back into easy conversations with each other. They paid for our drinks.

"

We shared our travel experiences thus far in Ireland, having visited both the nation and the territory, and got a local's perspective on things in return. The kids were mostly upset because they'd grown up in angry households, but the parents were violent for a cause; kids these days are angry, but the violence is senseless, untargeted. People were still fighting for nationalism, and a new form of IRA was coming about, but they were extremists and the real fight was being waged mostly with currency and politics, not weapons. As we asked questions, they increasingly responded with not answers, but stories. They made a point to note that they were all peaceful these days. What a strange thing to say. My instincts told me that we were onto something; at this point the parlance was especially curious, authoritative. Having made enough hints without a negative reaction, my new barmate took us to the flag on the wall and moved it aside, revealing a collage of photos from the 70s, 80s, and 90s. Promonently placed was a photo of him, a lit Molotov in one hand as he ran towards a British tank to scoop a child from its path. It looked like an image search for The Troubles in Derry, and the faces in those photos were recognizably sitting at the bar behind us. We learned history from the people who made it.


Amsterdam was a great combination of visiting old friends, making new friends, and meeting old friends for the first time, all wrapped up in an incredibly unique and beautiful city. But perhaps most importantly, Cindy got some pony time.


I'm a bit late catching up on feeds, but I came across Brent Simmons' post on Coalescing today and—having solved the same problem in a different way—thought I'd chime in.

Coalescing calls is great for things like data stores that are backed by an archive on disk, because you want every operation to call -synchronize when it's finished (for data integrity), but you also don't want it to be over-called (for performance). In my own use today, coalescing saved 75% of the disk writes in my test harness which, while obviously a contrived case, proved its usefuless immediately.

In my own limited experience, NSTimer or -performSelector:afterDelay: are a code smell1, and their use should be eliminated and replaced with something that is more appropriate to the problem being solved. In unit testing, I use dispatch_group to block tests until the side effects (in this case, delegate calls) have been completed as expected. For call coalescing—since I'm already using GCD for mutexing—I simply add a counter:

// Called on lockQueue, a serial dispatch queue.
- (void)synchronize;
{
    self.syncCount++;

    dispatch_async(lockQueue, ^{
        if (--self.syncCount == 0) {
            // Do your work here.
        }
    });
}

Super simple, and if you're already using dispatch queues for locking, which I highly recommend, all you need to add is a property. For a minor performance boost (avoiding Block_copy) replace dispatch_async with dispatch_async_f and the appropriate glue.


1 Although I can see an argument for their use for UI/animations, more often they're used to try to avoid race conditions that aren't understood or to queue something to run after the main thread's runloop has finished its current iteration2.
2 For which you should be using dispatch_async(dispatch_get_main_queue(), ^{ /* … */}) instead.