Skip to content

Instantly share code, notes, and snippets.

@advantis
Last active October 3, 2015 08:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save advantis/2428642 to your computer and use it in GitHub Desktop.
Save advantis/2428642 to your computer and use it in GitHub Desktop.
UIActionSheet subclass that brings simple block API
//
// Copyright © 2011 Yuri Kotov
//
#import <UIKit/UIKit.h>
typedef void(^ADVSheetAction) ();
@interface ADVActionSheet : UIActionSheet <UIActionSheetDelegate>
- (NSInteger) addButtonWithTitle:(NSString *)title action:(ADVSheetAction)action;
@end
//
// Copyright © 2011 Yuri Kotov
//
#import "ADVActionSheet.h"
#import <objc/runtime.h>
static inline BOOL ProtocolContainsSelector (Protocol *protocol, SEL selector)
{
return NULL != protocol_getMethodDescription(protocol, selector, NO, YES).name;
}
@interface ADVActionSheet ()
@property (nonatomic, strong) NSMutableArray *actions;
@property (nonatomic, weak) id<UIActionSheetDelegate> trueDelegate;
@end
@implementation ADVActionSheet
#pragma mark - ADVActionSheet
- (NSInteger) addButtonWithTitle:(NSString *)title action:(ADVSheetAction)action
{
NSInteger index = [super addButtonWithTitle:title];
self.actions[index] = action ?: (ADVSheetAction)^{};
return index;
}
/**
* UIActionSheet performs a series of "respondsToSelector" calls on delegate change
* to determine which of the optional protocol methods it implements and cache
* this info. Therefore we need to force it to update this info for a new delegate.
*/
- (void) refreshSupportedOptionalMethods
{
super.delegate = nil;
super.delegate = self;
}
#pragma mark - UIActionSheet
- (id<UIActionSheetDelegate>) delegate
{
return self.trueDelegate;
}
- (void) setDelegate:(id<UIActionSheetDelegate>)delegate
{
if (delegate != self.trueDelegate && delegate != self)
{
self.trueDelegate = delegate;
[self refreshSupportedOptionalMethods];
}
}
- (NSInteger) addButtonWithTitle:(NSString *)title
{
return [self addButtonWithTitle:title action:nil];
}
#pragma mark - NSObject
- (id) init
{
self = [super init];
if (self)
{
_actions = [[NSMutableArray alloc] initWithCapacity:4];
super.delegate = self;
}
return self;
}
- (BOOL) respondsToSelector:(SEL)selector
{
BOOL responds = [super respondsToSelector:selector];
if (!responds && ProtocolContainsSelector(@protocol(UIActionSheetDelegate), selector))
{
responds = [self.trueDelegate respondsToSelector:selector];
}
return responds;
}
- (id) forwardingTargetForSelector:(SEL)selector
{
return ProtocolContainsSelector(@protocol(UIActionSheetDelegate), selector)
? self.trueDelegate
: [super forwardingTargetForSelector:selector];
}
#pragma mark - UIActionSheetDelegate
- (void) actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if ([self.trueDelegate respondsToSelector:_cmd])
{
[self.trueDelegate actionSheet:actionSheet clickedButtonAtIndex:buttonIndex];
}
// Check for the case of tapping outside an action sheet on iPad
// Kudos to @parfeon for pointing this out
if (buttonIndex < [self.actions count])
{
((ADVSheetAction)self.actions[buttonIndex])();
}
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment