Objective-C
iOS

【デザインパターン】複数にデリゲートする方法 Multicast Delegate Pattern


Multicast Delegate Pattern

delegateは処理の一部を委譲するときに使うものです。

この通知先を複数にする方法を紹介します。


使用例

MultiDelegateProxy *delegateProxy = [[MultiDelegateProxy alloc] initWithTarget:self, nil];

[delegateProxy addTarget:xxx];
[delegateProxy addTarget:zzz];
self.scrollView.delegate = (id)delegateProxy;


実装例


MultiDelegateProxy.h

#import <Foundation/Foundation.h>


@interface MultiDelegateProxy : NSProxy
- (instancetype)initWithTarget:(NSObject *)targets, ... NS_REQUIRES_NIL_TERMINATION;
- (void)addTarget:(NSObject *)target;
- (void)removeTarget:(NSObject *)target;
@end



MultiDelegateProxy.m

#import "MultiDelegateProxy.h"


@interface MultiDelegateProxy ()
@property (strong, nonatomic) NSMutableArray* targets;
@end

@implementation MultiDelegateProxy

- (instancetype)initWithTarget:(NSObject *)targets, ... {
_targets = @[].mutableCopy;
va_list arguments;
va_start(arguments, targets);
NSObject *value = targets;
while (value) {
[_targets addObject:value];
value = va_arg(arguments, typeof(NSObject*));
}
va_end(arguments);
return _targets.count ? self : nil;
}

- (void)forwardInvocation:(NSInvocation *)invocation {
for(NSObject *target in _targets.copy) {
if ([target respondsToSelector:invocation.selector]) {
[invocation invokeWithTarget:target];
}
}
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
for(NSObject *target in _targets.copy) {
if ([target respondsToSelector:sel]) {
return [target methodSignatureForSelector:sel];
}
}
return nil;
}

- (BOOL)respondsToSelector:(SEL)aSelector {

if ([super respondsToSelector:aSelector]) {
return YES;
}

for(NSObject *target in _targets.copy) {
if ([target respondsToSelector:aSelector]) {
return YES;
}
}
return NO;
}

- (BOOL)conformsToProtocol:(Protocol *)aProtocol {
for(NSObject *target in _targets.copy) {
if ([target conformsToProtocol:aProtocol]) {
return YES;
}
}
return NO;
}

- (void)addTarget:(NSObject *)target {
if (target && ![_targets containsObject:target]) {
[_targets addObject:target];
}
}

- (void)removeTarget:(NSObject *)target {
if (target && [_targets containsObject:target]) {
[_targets removeObject:target];
}
}

@end



参考リンク


Article

http://blog.fenrir-inc.com/jp/2013/11/nsproxy.html

http://blog.scottlogic.com/2012/11/19/a-multicast-delegate-pattern-for-ios-controls.html

http://www.gregread.com/2016/02/23/multicast-delegates-in-swift/


OSS

https://github.com/tumtumtum/SwiftMulticastDelegate

https://github.com/jonasman/MulticastDelegate

Original