[Rubycocoa-devel 847] Re: CoreData.define_wrapper sometimes crashes

Zurück zum Archiv-Index

Pierce T. Wetter III pierc****@twinf*****
Mon Apr 16 01:36:52 JST 2007


On Apr 15, 2007, at 7:58 AM, Jacob Wallström wrote:

> I'm also having problems with CoreData.define_wrapper. I have
> isolated the problem to the following code:


   Hmmm... That's different behavior then what I've been seeing. I've  
been digging into this code the last few days with various iterations  
of the problem. I've come to the conclusion that a few minute thought  
needs to be put into thinking about KVC & NSManagedObject. It's  
probably going to be a problem Laurent will have to solve but I'll  
help where I can.

   The first problem I was having was because the define_wrapper  
code, which runs when a model file gets loaded ends up overwriting  
any accessor methods defined on the ruby side. Since rb_main.rb loads  
all the ruby files first, that meant that at model time my accessor  
methods had already been defined...

I was able to work around that by having the define_wrapper method  
check for definitions and NOT define a method if there was already  
one there as I posted earlier. I had to add my own version of  
valueForKey on the object as well.

   Once I got everything working, I switched to one of my existing  
data files instead of the simple test data file I was using. I then  
noticed how excruciatingly slow my app was.

   Running with the -d flag, I realized that crossing the bridge 3  
times every time I accessed a value in an NSManagedObject was  
excruciating:

  def foo
     willAccessValueForKey "foo"
     result= primitiveValueForKey "foo"
     didAccessValueForKey "foo"
     result
  end

  Since most of the data has standardized accessors, and mogenerator  
exists, I thought "well,
what I'll do is store those in an objective-C side object.

   Boom, lots of endless loops.

   Near as I can tell, the problem is that the rb<->cocoa bridge is  
relying on KVC to make its life easier. That is, if you do  obj.foo,  
somewhere that translates into obj.valueForKey("foo").

   The reason that causes endless loops is because it turns into:

    obj.foo -> obj.valueForKey("foo") -> obj.foo -> obj.valueForKey 
("foo")

    That is, it never makes the leap to turn into obj.oc_send("foo").  
Especially if define_wrapper has run, because it defines a bunch of  
accessors like this:

    def foo
       valueForKey "foo"
    end

    So if you have "foo" defined in an objective-c superclass, you  
hit an endless loop instead
of the above code. I guess that's because the responds_to? check I  
made doesn't show the methods from the Objective-C side?

    So I had to disable the define_wrapper entirely.

    The other problem I ran into was that:

    def foo
        super
    end

    Would also cause an endless loop. I guess that's a known thing,  
given that the docs all say
to use instead:

    def foo
       super_foo
    end

    So I think there's some sort of fundamental flaw with  
define_wrapper and the KVC stuff:

    1. As is, if you have defined/customized any accessors on the  
ruby side, define_wrapper blows them away. While it might be possible  
to tweak define_wrapper to not do that if it sees an existing  
definition using responds_to?, it really has to check for both the  
ruby and the objective-c side before creating the definition.

    2. If you have accessors on the objective-C side define_wrapper  
will cause an endless loop
rather then call them because it makes new accessors that call  
valueForKey instead which causes them to call the new accessor again.

    Now complicating this whole situation is the fact that accessors  
are _optional_ with Core Data as NSManagedObject will deal with them  
by default in valueForUndefinedKey. But I haven't experimented much  
with that. That may be why the Core Data sample projects seem OK, but  
its more typical for CoreData programmers to define all the accessors  
(especially with mogenerator), and then tweak only the ones that need  
custom logic.

  Pierce

  P.S.

    Hey Jason! Ghost Action is a Ruby Cocoa app? Cool! I'm porting  
Frictionless to RubyCocoa and making it open source. (http:// 
www.twinforces.com)




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