Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
277 views
in Technique[技术] by (71.8m points)

ios - Intercept Objective-C delegate messages within a subclass

I have a subclass of UIScrollView in which I need to internally respond to scrolling behaviour. However, the viewcontroller will still need to listen to scrolling delegate callbacks, so I can't outright steal the delegate within my component.

Is there a way to keep the property named "delegate" and just listen to messages sent along it, or else somehow internally hijack the delegate property and forward messages outward after running some code?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

To avoid overriding all of the delegate methods manually, you can use message forwarding. I just implemented the same thing using an intermediate proxy class as follows:

MessageInterceptor.h

@interface MessageInterceptor : NSObject {
    id receiver;
    id middleMan;
}
@property (nonatomic, assign) id receiver;
@property (nonatomic, assign) id middleMan;
@end

MessageInterceptor.m

@implementation MessageInterceptor
@synthesize receiver;
@synthesize middleMan;

- (id)forwardingTargetForSelector:(SEL)aSelector {
    if ([middleMan respondsToSelector:aSelector]) { return middleMan; }
    if ([receiver respondsToSelector:aSelector]) { return receiver; }
    return [super forwardingTargetForSelector:aSelector];
}

- (BOOL)respondsToSelector:(SEL)aSelector {
    if ([middleMan respondsToSelector:aSelector]) { return YES; }
    if ([receiver respondsToSelector:aSelector]) { return YES; }
    return [super respondsToSelector:aSelector];
}

@end

MyScrollView.h

#import "MessageInterceptor.h"

@interface MyScrollView : UIScrollView {
    MessageInterceptor * delegate_interceptor;
    //...
}

//...

@end

MyScrollView.m (Edited, with thanks to jhabbott):

@implementation MyScrollView

- (id)delegate { return delegate_interceptor.receiver; }

- (void)setDelegate:(id)newDelegate {
    [super setDelegate:nil];
    [delegate_interceptor setReceiver:newDelegate];
    [super setDelegate:(id)delegate_interceptor];
}

- (id)init* {
    //...
    delegate_interceptor = [[MessageInterceptor alloc] init];
    [delegate_interceptor setMiddleMan:self];
    [super setDelegate:(id)delegate_interceptor];
    //...
}

- (void)dealloc {
    //...
    [delegate_interceptor release];
    //...
}

// delegate method override:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    // 1. your custom code goes here
    // 2. forward to the delegate as usual
    if ([self.delegate respondsToSelector:@selector(scrollViewDidScroll:)]) {
        [self.delegate scrollViewDidScroll:scrollView];
    }
}

@end

With this approach, the MessageInterceptor object will automatically forward all delegate messages to the regular delegate object, except for the ones that you override in your custom subclass.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...