Как NSProxy "трансформируется в другой объект"?

Ссылка на класс NSProxy говорит следующее:

Как правило, сообщение прокси пересылается реальному объекту или заставляет прокси загружать (или преобразовывать себя) в реальный объект.

Как именно будет работать "преобразование себя в реальный объект"?

Чтобы сделать вещи более конкретными, предположим, что класс Foo имеет метод newFooWithString:, который берет строку и возвращает новый экземпляр Foo. Можно ли настроить NSProxy, который находится вокруг, и если получено сообщение pleaseBecomeAFooUsingString: @"bar", преобразуется в [Foo newFooWithString: @"bar"], занимая одну и ту же память, не вмешиваясь в другие ссылки на себя, которые могут существовать?

Ответ 1

Если у вас есть указатель на один и тот же экземпляр NSProxy по всему коду и будет "преобразовывать" его, он будет меняться по всему коду. Невозможно дифференцировать вызывающего метода для объекта, поэтому вы не сможете чередовать цели для перенаправления вызова методов в свой код автоматически. Общий преобразуемый прокси будет выглядеть следующим образом:

<суб > 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

Итак, что вы запросили, это своего рода кодовая магия, но NSProxy - это простой переадресатор сообщений, нет никакой магии, поэтому ваша цель не достижима так, как вы описали.

Ответ 2

Вы можете создать подкласс из NSProxy, который изменяет объект, на который он пересылает методы, на основе того, что вы хотите. Таким образом, объект object всегда будет указывать на NSProxy, но вы, возможно,BecomeAFooUsingString: изменит объект, который он перенаправляет как Foo.