From: Jonathan P. <jp...@dc...> - 2005-11-07 20:29:49
|
On 7 Nov 2005, at 19:00, Rupert BARROW wrote: > 2005-11-07 19:55:36.494 SimpleStickies[782] Exception syncing: > NSUnknownKeyException, reason [<Note 0x651130> takeValue:forKey:]: > attempt to assign value to unknown key: 'primaryKey'. > This class does not have an instance variable of the name > primaryKey or _primaryKey, nor a method of the name setPrimaryKey, > or _setPrimaryKey > > This is strange since dumping the instance_methods of Note shows > that all the expected methods are there : > setCreateDate > createDate I think these are ruby-level instance methods - not actually known to Objective C. The Objective C -> ruby bridge is accomplished through the ObjC equivalent of Ruby's method_missing. > > So, do you think that SyncServices are using some route which is > bypassing our kvc_wrapper mechanism to reach the primaryKey > "attribute" and getter and setter ? I think the problem is that SyncServices is indirectly checking the Objective C class for a method primaryKey or _primaryKey and failing because they don't exist. The key-value-coding support in RubyCocoa is implemented by hooking into the valueForUndefinedKey: method that KVC calls if such a method doesn't exist. It seems that SyncServices is using another route that doesn't use that method. (this is my guess - haven't looked into it further) It might be possible to resolve the problem, by defining the methods in question in Objective C land. There is a special RubyCocoa method to help you do this. Take a look at the kvc_array_accessor method declared in oc_import.rb. It uses addRubyMethod_withType to add a real ObjC method that calls through to a Ruby method. So you'd convert your kvc_wrapper_representation to look something like (untested): def kvc_wrapper_representation(*keys) keys.each do |key| set_key = "set" + key set_key[3..3] = set_key[3..3].upcase class_eval <<- EOE_KVC_WRAPPER_REPRESENTATION,__FILE__,__LINE__+1 def #{key} @_representation.valueForKey("#{key}") end def #{key}=(val) self.willChangeValueForKey("#{key}") @_representation.setValue_forKey(val, "#{key}") self.didChangeValueForKey("#{key}") end def #{set_key}(val); self.#{key}= val; end EOE_KVC_WRAPPER_REPRESENTATION self.addRubyMethod_withType("#{key}".to_sym, "@4@8:12") self.addRubyMethod_withType("# {set_key}:".to_sym, "@4@8:12@16") end end Having thought about this a bit more, it may be cleaner to 'improve' the implementation of kvc_reader and kvc_writer to define these methods and call through to the appropriate ruby setter/getter. Then you'd implement the delegation to @_representation in a normal ruby accessor. Hope that makes some sense :) Jonathan |