Question

I just want to get a selector name, and the arguments, sender, or an NSInvocation instance every time when I send a message to an object. Possible? Something like forwardInvocation:, but in evey case (every method call).

Was it helpful?

Solution

There is way to get the selector's name and the target by using the hidden parameters in objective-c messaging. From Apple's documentation:

When objc_msgSend finds the procedure that implements a method, it calls the procedure and passes it all the arguments in the message. It also passes the procedure two hidden arguments:

The receiving object The selector for the method

So in a method you can get the following:

   id  target = getTheReceiver();
   SEL method = getTheMethod();

If it's still not enough for your needs, you can do the following:

  1. Create a class called Helper.
  2. Add a reference to the class from where you will call the methods, in this format: id <HelperDelegate> myClassReference;
  3. When you need to make a [self method] instead create an instance of this Helper class and call the method on it like [helper method]; and add this [helper setMyClassReference:self];.
  4. The app should crash, but then, just add the forwardInvocation: on the Helper class. From there, you will be able to get the NSInvocation object. Do what you need to do, and then: [anInvocation invokeWithTarget:myClassReference]; so you can pass the message to the original caller.

P.S: Even if this doesn't answer your question, +1 for the question.. Really got me thinking about this.

OTHER TIPS

So I made this class, works like a charm.

.h

@protocol PGMessageObserverDelegate
-(void)observedInvocation:(NSInvocation*) invocation willSendToObject:(id) object;
-(void)observedInvocation:(NSInvocation*) invocation didSendToObject:(id) object;
@end


@interface PGMessageObserver : NSObject

@property (nonatomic, readonly) id observable;
@property (nonatomic, readonly) id <PGMessageObserverDelegate> delegate;

+(id)messageObserverObserving:(id) observable delegate:(id) delegate;

@end

.m

#import "PGMessageObserver.h"


@interface PGMessageObserver ()
-(id)initWithObservable:(id) observable delegate:(id) delegate;
@end


@implementation PGMessageObserver
@synthesize observable = _observable;
@synthesize delegate = _delegate;



#pragma mark - Creation

+(id)messageObserverObserving:(id) observable delegate:(id) delegate
{
    return [[[PGMessageObserver alloc] initWithObservable:observable delegate:delegate] autorelease];
}

-(id)initWithObservable:(id) observable delegate:(id) delegate
{
    if (self = [super init])
    {
        _observable = observable;
        _delegate = delegate;
    }
    return self;
}


#pragma mark - Message forwarding

-(void)forwardInvocation:(NSInvocation*) invocation
{
    //Notify.
    [_delegate observedInvocation:invocation willSendToObject:_observable];

        //Forward.
        if (_observable != nil)
        {
            [invocation invokeWithTarget:_observable];

            //Notify.
            [_delegate observedInvocation:invocation didSendToObject:_observable];
        }
}

-(NSMethodSignature*)methodSignatureForSelector:(SEL) selector
{
    return [_observable methodSignatureForSelector:selector];
}

@end

It is not as strict as it could be, but it notifies me about every action send to this observer, and the message then gets redirected to the original object (observable).

Client code is just a retained property...

@property (nonatomic, retain) PGMessageObserver *messageObserver;
#define self_OBSERVED _messageObserver

...and a setup somewhere.

self.messageObserver = [PGMessageObserver messageObserverObserving:self delegate:self];

Observable messages then should be sent to SELF_OBSERVED insted of self.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top