UIAlertView+BlocksKit.m 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. //
  2. // UIAlertView+BlocksKit.m
  3. // BlocksKit
  4. //
  5. #import "A2DynamicDelegate.h"
  6. #import "NSObject+A2BlockDelegate.h"
  7. #import "NSObject+A2DynamicDelegate.h"
  8. #import "UIAlertView+BlocksKit.h"
  9. #pragma mark Delegate
  10. @interface A2DynamicUIAlertViewDelegate : A2DynamicDelegate <UIAlertViewDelegate>
  11. @end
  12. @implementation A2DynamicUIAlertViewDelegate
  13. - (BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView
  14. {
  15. BOOL should = YES;
  16. id realDelegate = self.realDelegate;
  17. if (realDelegate && [realDelegate respondsToSelector:@selector(alertViewShouldEnableFirstOtherButton:)])
  18. should &= [realDelegate alertViewShouldEnableFirstOtherButton:alertView];
  19. BOOL (^block)(UIAlertView *) = [self blockImplementationForMethod:_cmd];
  20. if (block)
  21. should &= block(alertView);
  22. return should;
  23. }
  24. - (void)alertViewCancel:(UIAlertView *)alertView
  25. {
  26. id realDelegate = self.realDelegate;
  27. if (realDelegate && [realDelegate respondsToSelector:@selector(alertViewCancel:)])
  28. [realDelegate alertViewCancel:alertView];
  29. id key = @(alertView.cancelButtonIndex);
  30. void (^cancelBlock)(void) = (self.handlers)[key];
  31. if (cancelBlock)
  32. cancelBlock();
  33. }
  34. - (void)willPresentAlertView:(UIAlertView *)alertView
  35. {
  36. id realDelegate = self.realDelegate;
  37. if (realDelegate && [realDelegate respondsToSelector:@selector(willPresentAlertView:)])
  38. [realDelegate willPresentAlertView:alertView];
  39. void (^block)(UIAlertView *) = [self blockImplementationForMethod:_cmd];
  40. if (block)
  41. block(alertView);
  42. }
  43. - (void)didPresentAlertView:(UIAlertView *)alertView
  44. {
  45. id realDelegate = self.realDelegate;
  46. if (realDelegate && [realDelegate respondsToSelector:@selector(didPresentAlertView:)])
  47. [realDelegate didPresentAlertView:alertView];
  48. void (^block)(UIAlertView *) = [self blockImplementationForMethod:_cmd];
  49. if (block)
  50. block(alertView);
  51. }
  52. - (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
  53. {
  54. id realDelegate = self.realDelegate;
  55. if (realDelegate && [realDelegate respondsToSelector:@selector(alertView:willDismissWithButtonIndex:)])
  56. [realDelegate alertView:alertView willDismissWithButtonIndex:buttonIndex];
  57. void (^block)(UIAlertView *, NSInteger) = [self blockImplementationForMethod:_cmd];
  58. if (block)
  59. block(alertView, buttonIndex);
  60. }
  61. - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
  62. {
  63. id realDelegate = self.realDelegate;
  64. if (realDelegate && [realDelegate respondsToSelector:@selector(alertView:didDismissWithButtonIndex:)])
  65. [realDelegate alertView:alertView didDismissWithButtonIndex:buttonIndex];
  66. void (^block)(UIAlertView *, NSInteger) = [self blockImplementationForMethod:_cmd];
  67. if (block)
  68. block(alertView, buttonIndex);
  69. }
  70. - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
  71. {
  72. id realDelegate = self.realDelegate;
  73. if (realDelegate && [realDelegate respondsToSelector:@selector(alertView:clickedButtonAtIndex:)])
  74. [realDelegate alertView:alertView clickedButtonAtIndex:buttonIndex];
  75. void (^block)(UIAlertView *, NSInteger) = [self blockImplementationForMethod:_cmd];
  76. if (block)
  77. block(alertView, buttonIndex);
  78. id key = @(buttonIndex);
  79. void (^buttonBlock)(void) = (self.handlers)[key];
  80. if (buttonBlock)
  81. buttonBlock();
  82. }
  83. @end
  84. #pragma mark - Category
  85. @implementation UIAlertView (BlocksKit)
  86. @dynamic bk_willShowBlock, bk_didShowBlock, bk_willDismissBlock, bk_didDismissBlock, bk_shouldEnableFirstOtherButtonBlock;
  87. + (void)load
  88. {
  89. @autoreleasepool {
  90. [self bk_registerDynamicDelegate];
  91. [self bk_linkDelegateMethods:@{
  92. @"bk_willShowBlock": @"willPresentAlertView:",
  93. @"bk_didShowBlock": @"didPresentAlertView:",
  94. @"bk_willDismissBlock": @"alertView:willDismissWithButtonIndex:",
  95. @"bk_didDismissBlock": @"alertView:didDismissWithButtonIndex:",
  96. @"bk_shouldEnableFirstOtherButtonBlock": @"alertViewShouldEnableFirstOtherButton:"
  97. }];
  98. }
  99. }
  100. #pragma mark Convenience
  101. + (UIAlertView*)bk_showAlertViewWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSArray *)otherButtonTitles handler:(void (^)(UIAlertView *alertView, NSInteger buttonIndex))block
  102. {
  103. // If no buttons were specified, cancel button becomes "Dismiss"
  104. if (!cancelButtonTitle.length && !otherButtonTitles.count)
  105. cancelButtonTitle = NSLocalizedString(@"Dismiss", nil);
  106. UIAlertView *alertView = [[[self class] alloc] initWithTitle:title message:message delegate:self.bk_dynamicDelegate cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil];
  107. // Set other buttons
  108. [otherButtonTitles enumerateObjectsUsingBlock:^(NSString *button, NSUInteger idx, BOOL *stop) {
  109. [alertView addButtonWithTitle:button];
  110. }];
  111. // Set `didDismissBlock`
  112. if (block) alertView.bk_didDismissBlock = block;
  113. // Show alert view
  114. [alertView show];
  115. return alertView;
  116. }
  117. #pragma mark Initializers
  118. + (id)bk_alertViewWithTitle:(NSString *)title
  119. {
  120. return [self bk_alertViewWithTitle:title message:nil];
  121. }
  122. + (id)bk_alertViewWithTitle:(NSString *)title message:(NSString *)message
  123. {
  124. return [[[self class] alloc] bk_initWithTitle:title message:message];
  125. }
  126. - (id)bk_initWithTitle:(NSString *)title message:(NSString *)message
  127. {
  128. self = [self initWithTitle:title message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
  129. if (!self) return nil;
  130. self.delegate = self.bk_dynamicDelegate;
  131. return self;
  132. }
  133. #pragma Actions
  134. - (NSInteger)bk_addButtonWithTitle:(NSString *)title handler:(void (^)(void))block
  135. {
  136. NSAssert(title.length, @"A button without a title cannot be added to the alert view.");
  137. NSInteger index = [self addButtonWithTitle:title];
  138. [self bk_setHandler:block forButtonAtIndex:index];
  139. return index;
  140. }
  141. - (NSInteger)bk_setCancelButtonWithTitle:(NSString *)title handler:(void (^)(void))block
  142. {
  143. if (!title.length)
  144. title = NSLocalizedString(@"Cancel", nil);
  145. NSInteger cancelButtonIndex = [self addButtonWithTitle:title];
  146. self.cancelButtonIndex = cancelButtonIndex;
  147. [self bk_setHandler:block forButtonAtIndex:cancelButtonIndex];
  148. return cancelButtonIndex;
  149. }
  150. #pragma mark Properties
  151. - (void)bk_setHandler:(void (^)(void))block forButtonAtIndex:(NSInteger)index
  152. {
  153. id key = @(index);
  154. if (block)
  155. [self.bk_dynamicDelegate handlers][key] = [block copy];
  156. else
  157. [[self.bk_dynamicDelegate handlers] removeObjectForKey:key];
  158. }
  159. - (void (^)(void))bk_handlerForButtonAtIndex:(NSInteger)index
  160. {
  161. return [self.bk_dynamicDelegate handlers][@(index)];
  162. }
  163. - (void (^)(void))bk_cancelBlock
  164. {
  165. return [self bk_handlerForButtonAtIndex:self.cancelButtonIndex];
  166. }
  167. - (void)bk_setCancelBlock:(void (^)(void))block
  168. {
  169. if (block && self.cancelButtonIndex == -1) {
  170. [self bk_setCancelButtonWithTitle:nil handler:block];
  171. return;
  172. }
  173. [self bk_setHandler:block forButtonAtIndex:self.cancelButtonIndex];
  174. }
  175. @end