Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
iOS - UIButton+Block
//
// UIButton+Block.h
// BoothTag
//
// Created by Josh Holtz on 4/22/12.
// Copyright (c) 2012 Josh Holtz. All rights reserved.
//
#define kUIButtonBlockTouchUpInside @"TouchInside"
#import <UIKit/UIKit.h>
@interface UIButton (Block)
@property (nonatomic, strong) NSMutableDictionary *actions;
- (void) setAction:(NSString*)action withBlock:(void(^)())block;
@end
//
// UIButton+Block.m
// BoothTag
//
// Created by Josh Holtz on 4/22/12.
// Copyright (c) 2012 Josh Holtz. All rights reserved.
//
#import "UIButton+Block.h"
#import "/usr/include/objc/runtime.h"
@implementation UIButton (Block)
static char overviewKey;
@dynamic actions;
- (void) setAction:(NSString*)action withBlock:(void(^)())block {
if ([self actions] == nil) {
[self setActions:[[NSMutableDictionary alloc] init]];
}
[[self actions] setObject:block forKey:action];
if ([kUIButtonBlockTouchUpInside isEqualToString:action]) {
[self addTarget:self action:@selector(doTouchUpInside:) forControlEvents:UIControlEventTouchUpInside];
}
}
- (void)setActions:(NSMutableDictionary*)actions {
objc_setAssociatedObject (self, &overviewKey,actions,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSMutableDictionary*)actions {
return objc_getAssociatedObject(self, &overviewKey);
}
- (void)doTouchUpInside:(id)sender {
void(^block)();
block = [[self actions] objectForKey:kUIButtonBlockTouchUpInside];
block();
}
//
// UIButton+Block.h
// BoothTag
//
// Created by Josh Holtz on 4/22/12.
// Copyright (c) 2012 Josh Holtz. All rights reserved.
//
#define kUIButtonBlockTouchUpInside @"TouchInside"
#import <UIKit/UIKit.h>
@interface UIButton (Block)
@property (nonatomic, strong) NSMutableDictionary *actions;
- (void) setAction:(NSString*)action withBlock:(void(^)())block;
@end
//
// UIButton+Block.m
// BoothTag
//
// Created by Josh Holtz on 4/22/12.
// Copyright (c) 2012 Josh Holtz. All rights reserved.
//
#import "UIButton+Block.h"
#import "/usr/include/objc/runtime.h"
@implementation UIButton (Block)
static char overviewKey;
@dynamic actions;
- (void) setAction:(NSString*)action withBlock:(void(^)())block {
if ([self actions] == nil) {
[self setActions:[[NSMutableDictionary alloc] init]];
}
[[self actions] setObject:[block copy] forKey:action];
if ([kUIButtonBlockTouchUpInside isEqualToString:action]) {
[self addTarget:self action:@selector(doTouchUpInside:) forControlEvents:UIControlEventTouchUpInside];
}
}
- (void)setActions:(NSMutableDictionary*)actions {
objc_setAssociatedObject (self, &overviewKey,actions,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSMutableDictionary*)actions {
return objc_getAssociatedObject(self, &overviewKey);
}
- (void)doTouchUpInside:(id)sender {
void(^block)();
block = [[self actions] objectForKey:kUIButtonBlockTouchUpInside];
block();
}
...
[button setAction:kUIButtonBlockTouchUpInside withBlock:^{
NSString* launchUrl = @"http://joshholtz.com";
[[UIApplication sharedApplication] openURL:[NSURL URLWithString: launchUrl]];
}];
..

You need to copy the block to avoid the block to be garbage collected, see http://stackoverflow.com/questions/8852107/arc-related-crash-in-ios-when-using-a-block-pointer-as-a-member-variable

updated version at git://gist.github.com/2835270.git

Owner

joshdholtz commented Jun 1, 2012

Thanks combien! I actually did run across the issue and solved it with copying the block I just forgot to update my gist.

Thanks for the reminder though! Much appreciated.

Owner

joshdholtz commented Jun 1, 2012

Code is updated now to copy the block.

tacke758 commented Nov 2, 2013

I love this simple extension.
It's better to change the import path #import "/usr/include/objc/runtime.h" into #import <objc/runtime.h> in order to prevent build failure in Xcode5.

adamgit commented Nov 2, 2013

You only updated ONE of the missing "block copy" statemetns above. The UIButton+Block.m is broken.

Wouldn't it cause a retain cycle if you use self in the block implementation ?

@implementation ViewController
    //...
    [[self button] addAcction:kUIButtonBlockTouchUpInside  withBlock:^{
        [self doSomething];
    }]
    //...
@end

I'm asking because I'm trying to do something like this, and hate for the consumer of the control to always do :

__weak __typeof(self) weakSelf = self;
[[self button] addAcction:kUIButtonBlockTouchUpInside  withBlock:^{
    [weakSelf doSomething];
}]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment