Skip to content

Instantly share code, notes, and snippets.

@tokorom
Created December 26, 2013 07:00
Show Gist options
  • Select an option

  • Save tokorom/8130684 to your computer and use it in GitHub Desktop.

Select an option

Save tokorom/8130684 to your computer and use it in GitHub Desktop.

objc/runtimeの中でも安全度の高いやつを使ってみよう!

ふつうにActionSheetを使うと

UIActionSheet* sheet = [UIActionSheet new];
sheet.delegate = self;
[sheet addButtonWithTitle:@"action1"];
[sheet addButtonWithTitle:@"action2"];
[sheet addButtonWithTitle:@"Cancel"];
sheet.cancelButtonIndex = 2;
[sheet showInView:self.view];
sheet.tag = 'aaa';
- (void)actionSheet:(UIActionSheet*)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if (buttonIndex == actionSheet.cancelButtonIndex) {
        NSLog(@"pushed Cancel button.");
    }

    switch (actionSheet.tag) {
        case 'aaa':
           switch (buttonIndex) {
                case 0:
                    // 0のときはこう!
                    break;
                case 1:
                    // 1のときはこう!
                    break;
                default:
                    break;
            }
            break;
        case 'bbb':
           switch (buttonIndex) {
                case 0:
                    // 0のときはこう!
                    break;
                case 1:
                    // 1のときはこう!
                    break;
                default:
                    break;
            }
            break;
        default:
            break;
    }
}

できたらこうしたい

UIActionSheet* sheet = [UIActionSheet new];
[sheet addButtonWithTitle:@"action1"
                withBlock:^
{
    // action1の処理
}];
[sheet addButtonWithTitle:@"action2"
                withBlock:^
{
    // action2の処理
}];
[sheet addButtonWithTitle:@"Cancel"];
sheet.cancelButtonIndex = 2;
[sheet showInView:self.view];
sheet.tag = 'aaa';

カテゴリで拡張してみる

objc_setAssociatedObject がキーポイント

#import <objc/runtime.h>

const char UIActionSheetBlockPropertyPrefix[] = "UIActionSheet+Block.callbackBlocks";

- (NSInteger)addButtonWithTitle:(NSString *)title withBlock:(void (^)(void))block
{
    if (!self.delegate) {
        self.delegate = self;
    }

    NSUInteger buttonIndex = [self addButtonWithTitle:title];
    NSMutableDictionary *blocks = [self callbackBlocks];
    blocks[@(buttonIndex)] = block;
    return buttonIndex;
}

- (NSMutableDictionary *)callbackBlocks
{
    NSMutableDictionary *blocks = objc_getAssociatedObject(self, UIActionSheetBlockPropertyPrefix);
    if (!blocks) {
        blocks = [NSMutableDictionary dictionary];
        objc_setAssociatedObject(self, UIActionSheetBlockPropertyPrefix, blocks, OBJC_ASSOCIATION_RETAIN);
    }
    return blocks;
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if (actionSheet.cancelButtonIndex == buttonIndex) {
        return;
    }

    NSMutableDictionary *blocks = [actionSheet callbackBlocks];
    void (^block)() = blocks[@(buttonIndex)];
    if (block) {
        block();
    }
}

まとめ

  • objc/runtime.h を import してたら注意が必要
  • でもきちんと使えば強力
  • objc_setAssociatedObjectは副作用が少ない

オマケ

  • Xcode 5からは @import ObjectiveC; って書けるよ!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment