Skip to content

Instantly share code, notes, and snippets.

@jancassio
Last active April 13, 2017 15:04
Show Gist options
  • Save jancassio/8f190767414a84d281c1 to your computer and use it in GitHub Desktop.
Save jancassio/8f190767414a84d281c1 to your computer and use it in GitHub Desktop.
Simple UIButton Category to Support Event Blocks
// The MIT License (MIT)
// Copyright (c) 2014 Jan Cássio
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <UIKit/UIKit.h>
typedef void (^UIEventBlock)(id sender, UIEvent *event);
@interface UIButton (EventBlocks)
@property (nonatomic, copy) UIEventBlock onTouchUpInside;
@end
// The MIT License (MIT)
// Copyright (c) 2014 Jan Cássio
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "UIButton+EventBlocks.h"
#import <objc/runtime.h>
@interface UIButton (_EventBlocks_)
- (void)button:(UIButton *)button touchUpInsideWithEvent:(UIEvent *)event;
@end
@implementation UIButton (EventBlocks)
@dynamic onTouchUpInside;
static void *onTouchUpInsideKey = &onTouchUpInsideKey;
- (void)setOnTouchUpInside:(UIEventBlock)onTouchUpInside
{
if(onTouchUpInside)
{
objc_setAssociatedObject(self, onTouchUpInsideKey, onTouchUpInside, OBJC_ASSOCIATION_COPY_NONATOMIC);
[self addTarget:self action:@selector(button:touchUpInsideWithEvent:) forControlEvents:UIControlEventTouchUpInside];
}
else
{
objc_setAssociatedObject(self, onTouchUpInsideKey, nil, OBJC_ASSOCIATION_COPY_NONATOMIC);
[self removeTarget:self action:@selector(button:touchUpInsideWithEvent:) forControlEvents:UIControlEventTouchUpInside];
}
}
- (UIEventBlock)onTouchUpInside
{
return objc_getAssociatedObject(self, onTouchUpInsideKey);
}
- (void)button:(UIButton *)button touchUpInsideWithEvent:(UIEvent *)event
{
self.onTouchUpInside(button, event);
}
@end

#UIButton+EventBlocks

It's a simple category to implement event handler based in blocks.

Usage

1. Import UIButton+EventBlocks.h in your class

#import "UIButton+EventBlocks.h"

2. At any button instance of your class, you can handle UIControlEventTouchUpInside like this:

button.onTouchUpInside = ^(UIButton *button, UIEvent *event)
{
	// do something...
}

Also you can unlisten events if you pass nil as value for onTouchUpInside

button.onTouchUpInside = nil;

It's a very simple implementation for UIControlEventTouchUpInside, you can add blocks for any events you want, for example to add a handler block for UIControlEventTouchDown event, follow the steps:

1. Add a new property to category to access the block, onTouchDown is a good name for this

@property (nonatomic, copy) UIEventBlock onTouchDown;

2. Mark this call as @dynamic, without this, is impossible to bind the block

@dynamic onTouchDown;

3. Add a target handler in (EventBlocks) internal category

@interface UIButton (_EventBlocks_)

- (void)button:(UIButton *)button touchUpInsideWithEvent:(UIEvent *)event;
- (void)button:(UIButton *)button touchDownWithEvent:(UIEvent *)event;

@end

4. Add a pointer to set/get the reference for block

static void *onTouchDownKey = &onTouchDownKey;

5. Implement the setter method for onTouchDown property:

- (void)setOnTouchDown:(UIEventBlock)onTouchDown
{
  // If you pass nil
  if(onTouchDown)
  {
    objc_setAssociatedObject(self, onTouchDownKey, onTouchDown, OBJC_ASSOCIATION_COPY_NONATOMIC);
    [self addTarget:self action:@selector(button:touchDownWithEvent:) forControlEvents:UIControlEventTouchDown];
  }
  else
  {
    objc_setAssociatedObject(self, onTouchDownKey, nil, OBJC_ASSOCIATION_COPY_NONATOMIC);
    [self removeTarget:self action:@selector(button:touchDownWithEvent:) forControlEvents:UIControlEventTouchDown];
  }
}

6. Implement the getter method for onTouchDown property:

- (UIEventBlock)onTouchDown
{
  return objc_getAssociatedObject(self, onTouchDownKey);
}

7. Implement the target handler for UIControlEventTouchDown:

- (void)button:(UIButton *)button touchDownWithEvent:(UIEvent *)event
{
  self.onTouchDown(button, event);
}

Yes there is many steps to implement more callbacks but this will be handy in your day and this category is flexible enough for any project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment