Skip to content

Instantly share code, notes, and snippets.

@chakrit
Created October 14, 2012 03:54
Show Gist options
  • Save chakrit/3887222 to your computer and use it in GitHub Desktop.
Save chakrit/3887222 to your computer and use it in GitHub Desktop.
//
// ATInterceptor.h
// AddressTalk
//
// Created by Chakrit Wichian on 4/25/12.
// Copyright (c) 2012 Oozou Ltd. All rights reserved.
//
// ----
//
// Receives and relays any messages sent to it to the middleman if the
// middleman responds to it. Otherwise, the message is forwarded to the target.
// Useful for implementing multiple delegate objects for a single source.
//
// Adapted from: http://stackoverflow.com/a/3862591/3055
//
// NOTE: The interceptor itself *must* be retained in order to stay alive.
// Usually the middleman should be the one managing the interceptor's lifetime.
// This also means that the interceptor should be detached from all message
// sources before being de-alloc'ed to prevent messages being sent to
// dead instance.
//
// Also, the interceptor will retain neither the target nor the middleman,
// so it is expected that both is already retained by someone else.
//
@interface ATInterceptor : NSObject
@property (nonatomic, assign) id target;
@property (nonatomic, assign) id middleMan;
+ (id)interceptor;
+ (id)interceptorWithTarget:(id)target middleMan:(id)aMiddleMan;
- (id)init;
- (id)initWithTarget:(id)target middleMan:(id)aMiddleMan;
@end
//
// ATInterceptor.m
// AddressTalk
//
// Created by Chakrit Wichian on 4/25/12.
// Copyright (c) 2012 Oozou Ltd. All rights reserved.
//
#import "ATInterceptor.h"
@implementation ATInterceptor
@synthesize target=_target, middleMan=_middleMan;
+ (id)interceptor {
return [[[ATInterceptor alloc] init] autorelease];
}
+ (id)interceptorWithTarget:(id)target middleMan:(id)aMiddleMan {
return [[[ATInterceptor alloc] initWithTarget:target middleMan:aMiddleMan] autorelease];
}
- (id)init {
return [self initWithTarget:nil middleMan:nil];
}
- (id)initWithTarget:(id)target middleMan:(id)aMiddleMan {
// ensure we're not already intercepting the same target with the same middleman
BOOL already = [aMiddleMan isKindOfClass:[ATInterceptor class]];
already = already && ((ATInterceptor *)aMiddleMan).target == target;
if (already)
return aMiddleMan;
// we're safe, normal init
if (self = [super init]) {
self.target = target;
self.middleMan = aMiddleMan;
}
return self;
}
#pragma mark - Forwarding mechanism
- (id)forwardingTargetForSelector:(SEL)aSelector {
if ([_middleMan respondsToSelector:aSelector]) return _middleMan;
if ([_target respondsToSelector:aSelector]) return _target;
return [super forwardingTargetForSelector:aSelector];
}
- (BOOL)respondsToSelector:(SEL)aSelector {
if ([_middleMan respondsToSelector:aSelector]) return YES;
if ([_target respondsToSelector:aSelector]) return YES;
return [super respondsToSelector:aSelector];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment