Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Multicast Delegation

Multicast Delegation

NSLondon January 2014 PechaKucha

Luca Bernardi

January 16, 2014
Tweet

More Decks by Luca Bernardi

Other Decks in Programming

Transcript

  1. @interface LBDelegateMatrioska () @property (nonatomic, strong) NSPointerArray *mutableDelegates; @end !

    ! @implementation LBDelegateMatrioska ! - (instancetype)initWithDelegates:(NSArray *)delegates { _mutableDelegates = [NSPointerArray weakObjectsPointerArray]; [delegates enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { [_mutableDelegates addPointer:(void *)obj]; }]; return self; }
  2. @interface LBRViewController () @property (weak, nonatomic) IBOutlet MKMapView *mapView; @property

    (strong, nonatomic) LBDelegateMatrioska *delegateMatrioska; @property (strong, nonatomic) LBClusteredMapViewDelegate *clusteringDelegate; @end ! @implementation LBRViewController ! - (void)viewDidLoad { [super viewDidLoad]; ! self.delegateMatrioska = ({ self.clusteringDelegate = [LBClusteredMapViewDelegate new]; NSArray *delegates = @[self.clusteringDelegate, self]; LBDelegateMatrioska *matrioska = [[LBDelegateMatrioska alloc] initWithDelegates:delegates]; matrioska; }); self.mapView.delegate = (id<MKMapViewDelegate>)self.delegateMatrioska; }
  3. @implementation LBDelegateMatrioska ! ! #pragma mark - NSObject ! -

    (BOOL)respondsToSelector:(SEL)aSelector { id firstResponder = [self p_firstResponderToSelector:aSelector]; return (firstResponder ? YES : NO); }
  4. @implementation LBDelegateMatrioska ! #pragma mark - NSProxy ! - (void)forwardInvocation:(NSInvocation

    *)invocation { for (id delegate in self.mutableDelegates) { if ([delegate respondsToSelector:invocation.selector]) { [invocation invokeWithTarget:delegate]; } } } ! - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { id firstResponder = [self p_firstResponderToSelector:sel]; if (firstResponder) { return [firstResponder methodSignatureForSelector:sel]; } return nil; }
  5. #pragma mark - NSProxy ! - (void)forwardInvocation:(NSInvocation *)invocation { //

    If the invoked method return void I can safely call all the delegates // otherwise I just invoke it on the first delegate that // respond to the given selector if ([invocation methodReturnTypeIsVoid]) { for (id delegate in self.mutableDelegates) { if ([delegate respondsToSelector:invocation.selector]) { [invocation invokeWithTarget:delegate]; } } } else { id firstResponder = [self p_firstResponderToSelector:invocation.selector]; [invocation invokeWithTarget:firstResponder]; } }
  6. context(@"when a method is called", ^{ it(@"should be received by

    all the delegates that receive the message", ^{ SEL testSelector = @selector(didSelect); #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [[firstObject should] receive:testSelector]; [[secondObject should] receive:testSelector]; [[thirdObject shouldNot] receive:testSelector]; [(id <CannedProtocol>)matrioska performSelector:testSelector]; testSelector = @selector(didDeselect); [[firstObject shouldNot] receive:testSelector]; [[secondObject shouldNot] receive:testSelector]; [[thirdObject should] receive:testSelector]; [(id <CannedProtocol>)matrioska performSelector:testSelector]; #pragma clang diagnostic pop }); }); #import <Kiwi/NSProxy+KiwiVerifierAdditions.h>