Знать, когда объект создан

Есть ли способ использовать библиотеку времени выполнения ObjC или Cocoa для получения уведомлений при создании объекта, например, после его возврата из метода init?

Я хочу добиться этого без изменения объекта или его подкласса (например, без подкласса для NSObject) и без перебора методов (я уже знаю, как это сделать).


person LombaX    schedule 31.03.2013    source источник
comment
Не без кода в классе или каких-то вставок (таких как class_createInstance(), и в том числе swizzling), нет. Это не то, о чем вы обычно заботитесь, и если это так, вы должны иметь возможность изменить код. Можете ли вы уточнить свою конечную цель?   -  person jscs    schedule 01.04.2013
comment
Вы можете обернуть объект в экземпляр прокси и перенаправить селекторы к цели.   -  person CodaFi    schedule 01.04.2013


Ответы (2)


Не существует санкционированного способа получения уведомления о выполнении метода, если только он специально не указывает, что он возвращает уведомление или указатель на какой-либо обратный вызов, блок и т. д. Хотя swizzling может быть одним из способов сделать это, прокси-сервер вероятно, ваш лучший выбор. Вместо того, чтобы возиться с селектором для всего класса, вы вставляете себя «как» класс, реализуя все его свойства и/или перенаправляя селекторы целевому объекту. Таким образом, NSProxy и подклассы могут использоваться в качестве оболочек для обычных объектов, что означает, что вы можете реагировать на любой метод, который отправляется через ваш прокси, прежде чем перенаправить его на цель. Простой прокси можно смоделировать по образцу ниже:

FOUNDATION_EXPORT NSString *const CFIProxyDidInitializeTargetNotification;

@interface CFIObjectProxy : NSProxy {
    __strong Foo *_target;
}

- (id)init;

@property(nonatomic, readonly, retain) NSArray* bars;

@end

//...

#import "CFIObjectProxy.h"

NSString *const CFIProxyDidInitializeTargetNotification = @"CFIProxyDidInitializeTargetNotification";

@implementation CFIObjectProxy

- (id)init {

    _target = [[Foo alloc]init];
    [NSNotificationCenter.defaultCenter postNotificationName:CFIProxyDidInitializeTargetNotification object:nil];

    return self;
}

- (void)forwardInvocation:(NSInvocation *)invocation {
    [invocation invokeWithTarget:_target];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
    return [_target methodSignatureForSelector:sel];
}

- (NSString *)description {
    return [_target description];
}

- (NSString *)debugDescription {
    return [NSString stringWithFormat:@"<%@:%p> Proxy for Object: %@", NSStringFromClass(self.class), self, _target];
}

- (NSArray*)bars {
    return [_target bars];
}

@end
person CodaFi    schedule 31.03.2013
comment
Откуда - (NSArray *)bars? - person jscs; 01.04.2013
comment
Нужно ли мне действительно включать заголовок Foo? - person CodaFi; 01.04.2013
comment
Это закрытый метод? Это просто кажется ненужным, поскольку вы все равно все пересылаете. - person jscs; 01.04.2013
comment
Просто приятно показать, что вам не нужно полагаться на переадресацию. Это, и это позволяет вам использовать прокси, как если бы это был базовый объект. Xcode не слишком доволен прокси без явных свойств и т. д. - person CodaFi; 01.04.2013
comment
Спасибо, прокси-решение мне не подходит (я не могу добавить прокси вокруг объектов, они должны использоваться прозрачно), но на данный момент я понимаю, что нет других возможностей добиться этого без подкласса или swizzling... так что это правильный (и более полный) ответ :-) - person LombaX; 01.04.2013
comment
как я уже говорил ранее, это непрозрачно и доступно только для активных распределений - person Daij-Djan; 02.04.2013
comment
Несмотря на отсутствие прозрачности (что, можно сказать, не имеет значения), это решение намного безопаснее, чем переопределение методов, связанных с памятью, в классе. Swizzling +alloc, по сути, играет в русскую рулетку со средой выполнения, и все же за меня проголосовали? - person CodaFi; 02.04.2013

По умолчанию среда выполнения не записывает это. Я думаю, что я бы использовал swizzling, НО, поскольку вы этого не хотите ... Я думаю, что идея CodaFi обернуть объект в прокси-сервер лучше всего, хотя это только вариант для распределения, которое вы вручную делаете AFAICS

так что, если вы хотите, чтобы он был по-настоящему прозрачным, я бы сказал, в конце концов, swizzle

person Daij-Djan    schedule 31.03.2013