Skip to content

Instantly share code, notes, and snippets.

@hsavit1
Last active April 5, 2018 14:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hsavit1/d53a1d1b48be9661374d to your computer and use it in GitHub Desktop.
Save hsavit1/d53a1d1b48be9661374d to your computer and use it in GitHub Desktop.
Multicast Delegate Pattern in Objective C to add multiple delegates to something
#import "UITextViewHideKeyboardOnEnterBehaviour.h"
#import "UITextView+Multicast.h"
@implementation UITextViewHideKeyboardOnEnterBehaviour
- (id)initWithTextView:(UITextView *)textView
{
if (self=[super init])
{
[textView.multicastDelegate addDelegate:self];
}
return self;
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
// see: http://stackoverflow.com/questions/703754/how-to-dismiss-keyboard-for-uitextview-with-return-key
if([text isEqualToString:@"\n"]) {
[textView resignFirstResponder];
return NO;
}
return YES;
}
-(BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
return YES;
}
@end
// add multicasting capabilities to a UITextView
SHCMulticastDelegate* multicast = [[SHCMulticastDelegate alloc] init];
self.textView.delegate = multicast;
// add multiple delegates
[multicast addDelegate:_someDelegateImplementation];
[multicast addDelegate:_anotherDelegateImplementation];
#import <UIKit/UIKit.h>
#import "SHCMulticastDelegate.h"
@interface UITextView (Multicast)
@property (readonly) SHCMulticastDelegate* multicastDelegate;
@end
#import "UITextView+Multicast.h"
#import <objc/runtime.h>
@implementation UITextView (Multicast)
NSString* const UITextViewMulticastDelegateKey = @"multicastDelegate";
- (SHCMulticastDelegate *)multicastDelegate
{
// do we have a SHCMulticastDelegate associated with this class?
id multicastDelegate = objc_getAssociatedObject(self, (__bridge const void *)(UITextViewMulticastDelegateKey));
if (multicastDelegate == nil) {
// if not, create one
multicastDelegate = [[SHCMulticastDelegate alloc] init];
objc_setAssociatedObject(self, (__bridge const void *)(UITextViewMulticastDelegateKey), multicastDelegate, OBJC_ASSOCIATION_RETAIN);
// and set it as the delegate
self.delegate = multicastDelegate;
}
return multicastDelegate;
}
@end
#pragma mark - UIScrollViewDelegate forwarding
-(BOOL)respondsToSelector:(SEL)aSelector {
if ([self.delegate respondsToSelector:aSelector]) {
return YES;
}
return [super respondsToSelector:aSelector];
}
-(id)forwardingTargetForSelector:(SEL)aSelector {
if ([self.delegate respondsToSelector:aSelector]) {
return self.delegate;
}
return [super forwardingTargetForSelector:aSelector];
}
#import <Foundation/Foundation.h>
// handles messages sent to delegates, multicasting these messages to multiple observers
@interface SHCMulticastDelegate : NSObject
// Adds the given delegate implementation to the list of observers
- (void)addDelegate:(id)delegate;
@end
#import "SHCMulticastDelegate.h"
@implementation SHCMulticastDelegate
{
// the array of observing delegates
NSMutableArray* _delegates;
}
- (id)init
{
if (self = [super init])
{
_delegates = [NSMutableArray array];
}
return self;
}
- (void)addDelegate:(id)delegate
{
[_delegates addObject:delegate];
}
- (BOOL)respondsToSelector:(SEL)aSelector
{
if ([super respondsToSelector:aSelector])
return YES;
// if any of the delegates respond to this selector, return YES
for(id delegate in _delegates)
{
if ([delegate respondsToSelector:aSelector])
{
return YES;
}
}
return NO;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
// can this class create the signature?
NSMethodSignature* signature = [super methodSignatureForSelector:aSelector];
// if not, try our delegates
if (!signature)
{
for(id delegate in _delegates)
{
if ([delegate respondsToSelector:aSelector])
{
return [delegate methodSignatureForSelector:aSelector];
}
}
}
return signature;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
// forward the invocation to every delegate
for(id delegate in _delegates)
{
if ([delegate respondsToSelector:[anInvocation selector]])
{
[anInvocation invokeWithTarget:delegate];
}
}
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment