Pierce T. Wetter III
pierc****@twinf*****
Thu Apr 12 03:26:34 JST 2007
So the problem I was having was that my accessor methods written in ruby weren't getting called. I figured this was because oc_import.rb:502 was discarding them, called from cocoa_macros.rb:102 So I commented them out. Still no joy. Digging deeper, I found the following issues. Issue #1: Overly automatic implementation in rbSetValue_forKey rbSetValue_forKey is automatically wrapping any access method with willChangeValueForKey and didChangeValueForKey. This should really be left to the accessor method, or in ruby idiom, there should be a meta-programming method to declare this sort of default accessor, not mandatory. Work around: Redefine rbSetValue_forKey in your subclass. Issue #2: KVC/CoreData doesn't know about ruby accessors. Fixing the above won't help, because NSManagedObject/CoreData ends up never going into ruby at all, because the accessors are only called via "valueForUndefinedKey" or "setValue:forUndefinedKey:". With NSManagedObject, accessors are completely _optional_. If it can't find an accessor, it uses primitiveValueForKey instead. Workaround: I commented out the code at cocoa_macros.rb:102 that seemed to be blowing away MY accessors, and overrode the ruby version of NSManagedObject to look in ruby first before relying on the NSManagedObject implementation: # find accesor for key-value coding # "key" must be a ruby string def kvc_getter_method(key) [key, key + '?'].each do |m| return m if respond_to? m end return nil # accessor not found end def kvc_setter_method(key) [kvc_internal_setter(key), key + '='].each do |m| return m if respond_to? m end return nil end def kvc_accessor_notfound(key) fmt = '%s: this class is not key value coding-compliant for the key "%s"' raise sprintf(fmt, self.class, key.to_s) end def rbSetValue_forKey(value, key) if m = kvc_setter_method(key.to_s) send(m, value) else kvc_accessor_notfound(key) end end def valueForKey(key) print "aruby: valueForKey\n" if m = kvc_getter_method(key.to_s) return send(m) else super end end def setValue_forKey(value,key) print "aruby: setValue_forKey\n" if m = kvc_setter_method(key.to_s) send(m,value) else super end end Long term: I think that the ruby accessors need to be registered on the objective-C side, because one of the strengths of KVC is that it only is suppose to have to map key->accessor once. After that, it stores an association. Not sure how to do that though. Pierce