I hope people don't mind me posting this bit of code to the list, but I hope it 
will be of some use to others and would also be interested to hear if the 
technique has any problems which I've not foreseen.

Ruby has its own means of implementing the observer pattern, but as Key Value 
Observing (KVO) is so pervasive in cocoa, it would be good if it was easy to 
use. The module is an attempt at making KVO a bit more pleasant to use in 
macruby. 
The ideas have been adapted/stolen from here:

https://gist.github.com/153676

The following is an example of how to have a block of code executed 
asynchronously every time a property of an instance variable changes

self.add_observer_for_key_path('person.first_name', async:true) do 
|object,change|
    object.do_expensive_calculation #will not block main thread
end

A concern I do have is that the object which wants to receive KVO notifications 
holds an array of Observer objects. These Observer objects hold a reference to 
the object receiving the KVO notifications. Is this going to cause havoc with 
garbage collection?
 
module KVO

  class Observer
    require 'dispatch'

    attr_reader :observee, :path
    def initialize(object, path, async, block, opts=0)
      @observee = object
      @path = path
      @async = async
      @block = block              
      @observee.addObserver(self, forKeyPath:path, options:opts, context:nil)
    end

    def observeValueForKeyPath(path, ofObject:object, change:change, 
context:context)
      if @async
        Dispatch::Job.new { @block.call(object, change) } 
      else
        @block.call(object, change) 
      end
    end

    def cancel_observation
      @observee.removeObserver(self, forKeyPath:@path)
    end
  end

  def add_observer_for_key_path(path, async:async, &block)
    (@_observers_array_ ||= []) << Observer.new(self, path, async, block)
  end

  def add_observer_for_key_path(path, async:async, options:opts, &block)
    (@_observers_array_ ||= []) << Observer.new(self, path, async, block, opts)
  end

  def remove_observer_for_key_path(path)
    observer = @_observers_array_.find {|o| o.path == path && o.observee == 
self} if @_observers_array_
    @_observers_array_.delete(observer) and observer.cancel_observation if 
observer
  end
  
end
_______________________________________________
MacRuby-devel mailing list
MacRuby-devel@lists.macosforge.org
http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel

Reply via email to