[Rubycocoa-devel 841] Re: CoreData question (Workaround)

Zurück zum Archiv-Index

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




More information about the Rubycocoa-devel mailing list
Zurück zum Archiv-Index