Search code examples
objective-ccocoacocoa-touchnsproxy

How does NSProxy "transform itself into another object"?


The NSProxy Class Reference says this:

Typically, a message to a proxy is forwarded to the real object or causes the proxy to load (or transform itself into) the real object.

How exactly would the "transform itself into the real object" work?

To make things a little more specific, suppose class Foo has a method newFooWithString: that takes a string and returns a new instance of Foo. Would it be possible to setup an NSProxy that sits around, and if a pleaseBecomeAFooUsingString: @"bar" message is received, transforms itself into [Foo newFooWithString: @"bar"], occupying the same memory, without messing with other references to itself that may exist?


Solution

  • If you have a pointer to the same NSProxy instance all over the code and will "transform" it, it will change all over the code. There is no way to differentiate a caller of a method for an object, so you will not be able to alternate targets for forwarding of methods invocation in your code automatically. Common transformable proxy will looks in following way:

    MyTrickyProxy.h

    #import <Foundation/Foundation.h>
    
    @interface MyTrickyProxy : NSProxy {
        NSObject *object;
    }
    
    - (id)transformToObject:(NSObject *)anObject;
    
    @end
    

    MyTrickyProxy.m

    #import "MyTrickyProxy.h"
    
    @implementation MyTrickyProxy
    
    - (void)dealloc 
    {
        [object release];
        object = nil;
    
        [super dealloc];
    }
    
    - (NSString *)description 
    {
        return [object description];
    }
    
    //Stupid transform implementation just by assigning a passed in object as transformation target. You can write your factory here and use passed in object as id for object that need ot be created.
    - (id)transformToObject:(NSObject *)anObject 
    {
        if(object != anObject) {
            [object release];
        }
        object = [anObject retain];
    
        return object;
    }
    
    - (void)forwardInvocation:(NSInvocation *)invocation 
    {
        if (object != nil) {
            [invocation setTarget:object];    
            [invocation invoke];
        }
    }
    
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel 
    {
        NSMethodSignature *result;
        if (object != nil) {
            result = [object methodSignatureForSelector:sel];
        } else {
            //Will throw an exception as default implementation
            result = [super methodSignatureForSelector:sel];
        }
    
        return result;
    }
    
    @end
    

    So what you requested is some sort of code-magic, but NSProxy is a simple forwarder of a messages, there is no any magic at all, so your goal is not achievable in a way as you described.