Implementing a publish/subscribe design using the NSNotificationCenter

My background is mainly in Java, so if I want to create an object which has a set of listeners, I’m used to having to implement that design myself.  In the past, I’ve added a collection of listeners to the observable object, then added some methods to the class’ API to allow other objects to register as listeners for events.

I’m still quite new to iOS, so I haven’t really made a lot of use of NSNotificationCenter up till now, other than for registering for things like keyboard events.  I’ve found that it can really help with the publish/subscribe design pattern, and it reduces the amount of code you have to write.

To register an object to listen for a particular kind of event, you can use the following code:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(someMethod) name:kNotificationName object:nil];

You define the method in your listener class.  You pass in the name of notifications to listen for.  This means that whenever you post a notification with that name, the listeners which have registered for those kind of notifications will be notified.

To post a notification, you can use the following code:

[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:kNotificationName object:nil]];

The other thing to remember is to remove your listener classes as observers to the notification center when they are deallocated.

MacRuby and CoreData

As part of a project I’ve been working on, we’ve needed to use CoreData within MacRuby.     MacRuby is an implementation of Ruby which runs on the Objective-C runtime and the CoreFoundation framework.  As such, it allows you to make calls to CoreData within Ruby.

We created a utility class to allow us to make calls to our data store.  It was as follows:

class CoreDataStore
    def create_entity name, props={}, relationships={}
        entity = OSX::NSEntityDescription.insertNewObjectForEntityForName_inManagedObjectContext(name, context)
        props.each do |k,v|
            entity.setValue_forKey v,k
        end

        relationships.each do |k, objects|
            collection = entity.mutableSetValueForKey(k)
            objects.each {|o| collection.addObject o}
        end
        entity
    end

    def get_entity name, key, value
        request = OSX::NSFetchRequest.alloc.init

        description = OSX::NSEntityDescription.entityForName_inManagedObjectContext(name, context)

        request.setEntity(description)

        valueString = "#{value}"
        if (value.is_a? String)
            valueString = "'#{value}'"
        end
        predicateString = "#{key} like[c] #{valueString}"
        predicate = OSX::NSPredicate.predicateWithFormat(predicateString)

        request.setPredicate(predicate)

        error = nil

        result = context.executeFetchRequest_error(request, error)
    end

    def initialize(data_store_path, mom_path)
        @data_store_path = data_store_path
        @mom_path = mom_path
    end

    def context
        @contect ||= OSX::NSManagedObjectContext.alloc.init.tap do |context|
            model = OSX::NSManagedObjectModel.alloc.initWithContentsOfURL(
                OSX::NSURL.fileURLWithPath(@mom_path))
            coordinator = OSX::NSPersistentStoreCoordinator.alloc.initWithManagedObjectModel(model)

            result, error = coordinator.addPersistentStoreWithType_configuration_URL_options_error(
                OSX::NSSQLiteStoreType, nil, OSX::NSURL.fileURLWithPath(@data_store_path), nil)
            if !result
                raise "Add persistent store failed: #{error.description}"
            end
            context.setPersistentStoreCoordinator coordinator
        end
    end

    def save
        res, error = context.save_
        if !res
            raise "Save failed: #{error.description}"
        end
        res
    end
end

The utility class allows us to create a new entity within the persistent store, and to make a simple query on the store.  It is by no means comprehensive, but this did everything we needed in our simple use case.

Updating remote tracking branches on Git

I recently experienced some odd behaviour with Git and Gerrit.  I created a short-lived branch on a project in Gerrit.  Once I was done with it, I deleted the branch using the Gerrit admin page.

When I listed the remote branches for the project (using git branch -a), it was still showing the remote branch which I deleted!  Eventually, after a bit of research online, I found what the problem was.   The branch had been deleted on the remote repository, but I hadn’t yet updated my remote tracking branches yet.  Calling “git fetch” or “git pull” won’t update them either.  To do this, you need to call:

git remote prune origin

(For a remote with a different name, substitute it in for origin).  This deletes any stale remote tracking branches.