1

Is there any way to use the ObjC runtime library, or Cocoa, to be notified when an object is created, for example, after it returns from the init method?

I want to achieve this without modifying the object, or subclassing it (no subclass on NSObject, for example) and without method swizzling (I already know how to do that).

jscs
  • 63,694
  • 13
  • 151
  • 195
LombaX
  • 17,265
  • 5
  • 52
  • 77
  • Not without code in the class or _some_ kind of interposing (such as of `class_createInstance()`, and including swizzling), no. This isn't something you would normally care about, and if it is you should be able to change the code. Can you elaborate on your end goal? – jscs Mar 31 '13 at 20:13
  • You could wrap the object in a proxy instance and forward selectors through to the target. – CodaFi Mar 31 '13 at 20:18
  • @JoshCaswell , I'm working on a class that simulates the private _UIAppearance behavior. This to add UIAppearance support to objects that usually doesn't support it (look at this post: [link](http://stackoverflow.com/questions/15732885/uiappearance-proxy-for-custom-objects) ). I've just created a proxy class and it works good, but I would like to inject the invocations "automatically" after the target object is initialized, without calling the "startForwarding" method from the initialized object itself. But this is only for convenience, so I was looking for a "non invasive" method) – LombaX Mar 31 '13 at 20:43

2 Answers2

1

Per default, the runtime doesn't record this. I think I'd use swizzling BUT as you don't want this... I think that CodaFi's idea of wrapping the object in a proxy is best ALTHOUGH this is only an option for allocations you manually do AFAICS

so if you want it to be truly transparent, swizzle after all I'd say

Daij-Djan
  • 49,552
  • 17
  • 113
  • 135
1

There is no sanctioned way to be notified when a method executes, unless it specifically notes that it returns a notification, or a pointer to some kind of callback, a block, etc. While swizzling may be one way of going about it, proxying is probably your best bet. Instead of messing with the selector for an entire class, you interpose yourself "as" the class by implementing all its properties and/or forwarding selectors to the target object. In this way, NSProxy and subclasses can be used as wrappers around normal objects, meaning you can respond to any kind of method that happens to be sent through your proxy before forwarding it on to the target. A simple proxy can be modeled after the sample below:

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
CodaFi
  • 43,043
  • 8
  • 107
  • 153
  • Where does `- (NSArray *)bars` come from? – jscs Mar 31 '13 at 20:40
  • Need I really include the header of Foo? – CodaFi Mar 31 '13 at 20:41
  • It's a covered method? That just seems unnecessary since you're forwarding everything anyways. – jscs Mar 31 '13 at 20:42
  • Just nice to show that you don't have to rely on forwarding. That, and it allows you to use the proxy as though it were the underlying object. Xcode is none too happy about proxies without explicit properties, etc. – CodaFi Mar 31 '13 at 20:43
  • Thanks, the proxy solution is not good for me (I can't add a proxy around objects, they must be used transparently), but at this point I understand that there are no other possibilities to achieve it without subclassing or swizzling...so this is the correct (and more complete) answer :-) – LombaX Mar 31 '13 at 21:29
  • as I said earlier, this isn't transparent and only an option for active allocations – Daij-Djan Apr 02 '13 at 08:00
  • Despite its lack of transparency (which, one could argue, is besides the point), this solution is far safer than overriding the memory-related methods in a class. Swizzling +alloc is basically playing a game of Russian roulette with the runtime, and yet I get downvoted? – CodaFi Apr 02 '13 at 13:00