RACDelegateProxy.m 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. //
  2. // RACDelegateProxy.m
  3. // ReactiveCocoa
  4. //
  5. // Created by Cody Krieger on 5/19/12.
  6. // Copyright (c) 2012 GitHub, Inc. All rights reserved.
  7. //
  8. #import "RACDelegateProxy.h"
  9. #import "NSObject+RACSelectorSignal.h"
  10. #import <objc/runtime.h>
  11. @interface RACDelegateProxy () {
  12. // Declared as an ivar to avoid method naming conflicts.
  13. Protocol *_protocol;
  14. }
  15. @end
  16. @implementation RACDelegateProxy
  17. #pragma mark Lifecycle
  18. - (instancetype)initWithProtocol:(Protocol *)protocol {
  19. NSCParameterAssert(protocol != NULL);
  20. self = [super init];
  21. if (self == nil) return nil;
  22. class_addProtocol(self.class, protocol);
  23. _protocol = protocol;
  24. return self;
  25. }
  26. #pragma mark API
  27. - (RACSignal *)signalForSelector:(SEL)selector {
  28. return [self rac_signalForSelector:selector fromProtocol:_protocol];
  29. }
  30. #pragma mark NSObject
  31. - (BOOL)isProxy {
  32. return YES;
  33. }
  34. - (void)forwardInvocation:(NSInvocation *)invocation {
  35. [invocation invokeWithTarget:self.rac_proxiedDelegate];
  36. }
  37. - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
  38. // Look for the selector as an optional instance method.
  39. struct objc_method_description methodDescription = protocol_getMethodDescription(_protocol, selector, NO, YES);
  40. if (methodDescription.name == NULL) {
  41. // Then fall back to looking for a required instance
  42. // method.
  43. methodDescription = protocol_getMethodDescription(_protocol, selector, YES, YES);
  44. if (methodDescription.name == NULL) return [super methodSignatureForSelector:selector];
  45. }
  46. return [NSMethodSignature signatureWithObjCTypes:methodDescription.types];
  47. }
  48. - (BOOL)respondsToSelector:(SEL)selector {
  49. // Add the delegate to the autorelease pool, so it doesn't get deallocated
  50. // between this method call and -forwardInvocation:.
  51. __autoreleasing id delegate = self.rac_proxiedDelegate;
  52. if ([delegate respondsToSelector:selector]) return YES;
  53. return [super respondsToSelector:selector];
  54. }
  55. @end