discuss-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: @dynamic property synthesis


From: David Chisnall
Subject: Re: @dynamic property synthesis
Date: Mon, 6 Aug 2012 16:05:37 +0100

On 6 Aug 2012, at 09:51, Ivan Vučica wrote:

> Unless I'm misunderstanding again, I need to replicate the behavior of 
> CALayer by adding accessor methods at runtime. I can do that in two ways: 
> adding methods to the class at runtime, or intercepting an attempt to call an 
> unknown method (via -forwardInvocation:). If I'm adding a method, it needs to 
> be there; whether it's created in +initialize or in -forwardInvocation: 
> doesn't really matter. No matter how I'm using forwarding mechanisms, I need 
> to detect that it's an attempt to call an accessor.

It is most likely that Apple has implemented this via the 
+resolveInstanceMethod: (which should also work for us).  This basically lets 
you lazily add methods, and is faster than the -forwardInvocation: method.  The 
addition of methods like this is an optimisation though - don't worry about it 
too much because it's not essential, just a nice speedup for certain uses (and, 
to be honest, when you're throwing data across a PCIe bus, a couple of 
-forwardInvocation: calls are going to be in the noise, performance-wise).  

Now, the good news is that this code is actually easier to implement on GNUstep 
than OS X.  On OS X, they must use property introspection to find what the 
selector should be.  We don't need to do that, because the type of the method 
can be determined from the selector.  

The easiest way to implement this sort of thing on older systems is to have a 
placeholder class, something like _CALayer, with accessor methods for a few 
types (basically, integer and float types, plus objects).  You then can just 
copy this method to the correct place.

With the GNUstep runtime (or the OS X 10.7 / iOS 5 runtime), however, it's even 
easier.  You can use imp_implementationWithBlock() to generate the method for a 
block[1].  This means that you can bind the ivar to the method, so you don't 
have to do a dynamic call every time.  Something like this would work for the 
trivial case of just adding accessors for objects:

+ (BOOL)resolveInstanceMethod:(SEL)name
{
        // Look up the ivar, this is a pointer to something in the runtime, so 
never freed
        Ivar ivar = class_getInstanceVariable(self, sel_getName(name));
        // This binds the ivar, so when it's used it is very cheap to access
        id(^idBlock)(id Self) { return object_getIvar(Self, ivar);  }
        // Now we get an IMP from the block
        IMP imp = imp_implementationWithBlock(idBlock);
        // And add the IMP to class
        class_addMethod(self, name, imp, sel_getType_np(name));
        // And it worked (well, we assume so - error checking in the real 
version!), so let the runtime know that it should redo the lookup.
        return YES;
}

Note that for set methods you will need to extract the ivar name by removing 
the leading set and changing the case of the first letter - probably easier to 
go via an NSString for that.

Note also that this code path doesn't need optimising - it will only ever be 
called once for each property, so it can be relatively slow as long as the 
block it returns is simple.

Also note that I typed this code into my mail client and haven't tried 
compiling it - it is for illustrative use only!

David

[1] http://etoileos.com/news/archive/2011/11/10/1426/

-- Sent from my Apple II




reply via email to

[Prev in Thread] Current Thread [Next in Thread]