每个对象有多个代理?

时间:2012-01-25 08:42:29

标签: iphone objective-c ios cocoa-touch delegates

我有一个UIScrollView我需要子类,在子类中我需要附加UIScrollViewDelegate所以我可以实现viewForZoomingInScrollView方法。

然后我有一个UIViewController我需要实例化我创建的这个UIScrollView子类的对象,我还想让UIViewController成为这个对象的UIScrollViewDelegate所以我可以在此scrollViewDidZoom课程中实施UIViewController

如何让一个对象有两个委托? (我知道我可以很容易地只有一个代表并且只在那里实现这两种方法,但出于设计目的,我想按照我提到的方式来实现)。

5 个答案:

答案 0 :(得分:14)

有时将多个委托附加到滚动视图是有意义的。在这种情况下,您可以构建一个简单的委托拆分器:

// Public interface
@interface CCDelegateSplitter : NSObject

- (void) addDelegate: (id) delegate;
- (void) addDelegates: (NSArray*) delegates;

@end

// Private interface
@interface CCDelegateSplitter ()
@property(strong) NSMutableSet *delegates;
@end

@implementation CCDelegateSplitter

- (id) init
{
    self = [super init];
    _delegates = [NSMutableSet set];
    return self;
}

- (void) addDelegate: (id) delegate
{
    [_delegates addObject:delegate];
}

- (void) addDelegates: (NSArray*) delegates
{
    [_delegates addObjectsFromArray:delegates];
}

- (void) forwardInvocation: (NSInvocation*) invocation
{
    for (id delegate in _delegates) {
        [invocation invokeWithTarget:delegate];
    }
}

- (NSMethodSignature*) methodSignatureForSelector: (SEL) selector
{
    NSMethodSignature *our = [super methodSignatureForSelector:selector];
    NSMethodSignature *delegated = [(NSObject *)[_delegates anyObject] methodSignatureForSelector:selector];
    return our ? our : delegated;
}

- (BOOL) respondsToSelector: (SEL) selector
{
    return [[_delegates anyObject] respondsToSelector:selector];
}

@end

然后只需将此拆分器的实例设置为滚动视图的委托,并将任意数量的委托附加到拆分器。所有人都将收到代表团的活动。一些注意事项适用,例如假设所有代理都属于同一类型,否则您将无法实现天真的respondsToSelector实现。这不是一个大问题,很容易将实现更改为仅向支持它们的人发送委托事件。

答案 1 :(得分:7)

您不希望具有2个委托的对象。您希望保持customScrollView对其自己的UIScrollViewDelegate函数负责。

要使您的parentVC响应UIScrollView的委托方法,您还必须在customScrollView中创建自定义委托。

在调用UIScrollViewDelegate函数时,您还将从自定义委托调用您的一个委托函数。这样你的parentVC就会在你想要的时候做出回应。

看起来有点像这样。

CustomScrollView.h

@protocol CustomDelegate <NSObject>

//custom delegate methods
-(void)myCustomDelegateMethod;

@end

@interface CustomScrollView : UIScrollView <UIScrollViewDelegate>
{
    id<CustomDelegate> delegate
    //the rest of the stuff

CustomScrollView.m

-(void) viewForZoomingInScrollView
{
    [self.delegate myCustomDelegateMethod];
    //rest of viewForZoomingInScrollView code

ParentVC.h

@interface CustomScrollView : UIViewController <CustomDelegate>
{
    //stuff

ParentVC.m

-(void)makeCustomScrollView
{
     CustomScrollView *csv = [[CustomScrollView alloc] init];
     csv.delegate = self;
     //other stuff

}

-(void)myCustomDelegateMethod
{
   //respond to viewForZoomingInScrollView
}

我希望这完全涵盖你的问题。 祝你好运。

答案 2 :(得分:3)

简短回答:你没有。代表们通常是一对一的弱关系:

@property (nonatomic, weak /*or assign*/) id<MyViewDelegate> delegate;

有时你会看到一个“听众”设计模式,这是一对多的代表形式:

- (void) addListener:(id<MyViewListener>)listener;
- (void) removeListener:(id<MyViewListener>)listener;

在您的情况下,UIScrollView中似乎没有一个很好的公共覆盖点,它允许子类指定viewForZoomingInScrollView。如果可能的话,我会避免让UIScrollView成为自己的委托。你可以让UIViewController成为UIScrollViewDelegate并让它提供viewForZooming。或者您可以创建一个使用UIScrollView的中间视图子类,提供viewForZooming,并转发其他委托方法。

答案 3 :(得分:2)

我认为你不能让两个UIScrollViewDelegate代表直接连接到同一个对象。

你可以做的是让两个代表连锁。即,您将一个委托连接到另一个委托,然后在它无法直接处理它们时将前一个转发消息发送给后者。

在任何情况下,我认为我都缺少一点来完全建议一个解决方案,即你确实需要第二个代表并且不能总是通过一个代表完成的原因。换句话说,我认为可能存在避免需要两名代表的替代设计。

答案 4 :(得分:0)

这是您正在尝试做的另一个潜在问题...

假设您有两个UIScrollView实例和一个委托对象。在委托对象中,您将重写UIScrollViewDelegate协议的scrollViewDidScroll(UIScrollView *):方法。

在该方法内部,您想访问两个滚动视图的contentOffset属性的值,因为可能有两个相邻的collections视图,并且您试图将该项的索引路径获取到集合视图以获取与这两项关联的属性的值(请考虑UIDatePicker)。

在这种情况下,滚动视图之间有何区别? scrollView属性仅引用一个滚动视图。但是,即使同时引用了两者,您如何获得它们各自的contentOffset属性的值?

现在,您可能会说:“我可以为两者创建一个IBOutlet,并使用它们分配的引用而不是委托方法中的scrollView属性(例如self.collectionViewFirst.contentOffset和self.collectionViewSecond.contentOffset),并忽略委托方法的scrollView属性。

问题是这样的:不存储该属性。仅在调用委托方法时可用。为什么?因为只有一个委托对象,并且只有一个contentOffset属性。通过滚动另一个滚动视图,contentOffset属性的值将更改,并且不会反映除最后一个滚动视图以外的任何其他滚动视图的内容偏移。

即使我所描述的情况(或类似情况)不适用于您的情况,也很难按照自己的意愿去做。请记住:编写代码是关于共享代码。错误的代码会向他人发送一条消息,从而降低您的声誉。