如何在Objective-C中的子类中拦截和转发委托消息?

时间:2016-06-17 05:03:38

标签: ios objective-c uiscrollview delegates objective-c-runtime

我想在Objective-C中实现UIScrollView的子类,比如MyScrollView

如何在MyScrollView的实现中透明地拦截从UIScrollView发送给委托的消息?所以代表不会意识到拦截,好像没有发生任何事情。

我尝试在Objective-C运行时使用消息转发。我将MyScrollView作为代理代理,拦截,处理然后转发消息,但似乎事情并没有按照我的想法发挥作用。

P.S。我想公开所有方法,就像超类(UIScrollView只是一个例子)一样。并且委托不应该错过任何新消息,这些消息可能会在未来修改子类的实现时添加到超类中。

2 个答案:

答案 0 :(得分:0)

首先,这是一个非常糟糕的主意。

如果没有100%透明度,您不应该这样做,代码的用户将无法理解由于此而导致内部中断的事情。

这是您应该尝试的推荐方法。

MyScrollView.h

#import <UIKit/UIKit.h>

@class MyScrollView;
@protocol MyScrollViewDelegate <NSObject>

// We will add 'msv_' to all our delegate callbacks
// So it doesn't clash with any of the original 'UIScrollViewDelegate' callbacks
@optional
-(void)msv_scrollViewDidScroll:(MyScrollView *)scrollView;

// You also need to carefully port the 'NS_AVAILABLE_IOS' with each method
// So it's explicitly clear to your users about the availability of a callback
-(void)msv_scrollViewDidZoom:(MyScrollView *)scrollView NS_AVAILABLE_IOS(3_2);

@end


@interface MyScrollView : UIScrollView

// We don't need to set a 'delegate' as that would point to a 'UIScrollView.delegate'
// We are making it explicitly clear what we are doing
@property(nonatomic,weak) id<MyScrollViewDelegate> msvDelegate;


@end

MyScrollView.m

#import "MyScrollView.h"

@interface MyScrollView () <UIScrollViewDelegate>

@end

@implementation MyScrollView

// This will get called whenever your scrollView subclass is added to a view
-(void)didMoveToSuperview
{
    [super didMoveToSuperview];

    // Set the delegate for 'UIScrollView' to be self.
    // We will receive all the callbacks from UIScrollView
    // And conditionally forward those to our msvDelegate as needed
    self.delegate = self;
}


#pragma mark - UIScrollViewDelegate Methods

-(void)scrollViewDidScroll:(UIScrollView*)scrollView
{
    // You can do your needed action ***BEFORE*** forwarding a call to your delegate

    if([_msvDelegate respondsToSelector:@selector(msv_scrollViewDidScroll:)])
        [_msvDelegate msv_scrollViewDidScroll:self];

    // You can do your needed action ***AFTER*** forwarding a call to your delegate
}


@end

好吧,一开始可能看起来有点冗长,但从长远来看它会付出代价。您可以通过这种方法保证您不会弄乱运行时,如果以后出现任何问题,您可以立即修复。你只是添加一个抽象层,就是这样。

还不够好吗?你必须阅读@mattt -

这篇伟大的文章

Method Swizzling - NSHipster

答案 1 :(得分:0)

委托是负责更新模型的对象,因此它应该是控制器对象而不是视图,因此不是UIScrollView子类。

改为创建类NSObject <UIScrollViewDelegate>。然后,某人可以在其UIViewController中创建其实例,并将其设置为滚动视图的委托。如果他们还想响应委托方法,则可以将其UIViewController设置为委托,然后将方法调用转发到您的UIScrollViewDelegate实现子类,或者他们可以只是将您的对象子类化以减少代码在他们的视图控制器中。