Runtime实现动态关联对象

引言

关于笔者对Runtime的理解,将在下一篇博文中与大家分享。
该篇博文,笔者将向大家分享一个Runtime实用的技巧,在实际开发中也会经常用到。

说明

假设你现在需要实用一个系统的类,UIButton,UILabel等,但是你觉得系统的类无法满足你的需求,你将会怎么做?
一般我们都会想到继承,确实这个可以实现。但是只是为了增加一个属性,而去继承一个类,未免太麻烦,要是类多了,管理维护也是很头疼的一件事。这个时候,runtime的关联对象就发挥了作用。
今天在这篇博文中,我给系统UIButton扩大点击范围,希望能给大家带来此方法其他作用实现的一个思路。

实战

1.给UIButton添加一个分类。

(分类是什么在此就不赘述,对类别的深入理解请移步category详解)

#import <UIKit/UIKit.h>

@interface UIButton (IncreaseTapArea)

- (void)addIncreaseTapAreaWithTop:(CGFloat)top buttom:(CGFloat)buttom left:(CGFloat)left right:(CGFloat)right;


@end

实现文件如下:

1.导入runtime头文件

#import "UIButton+IncreaseTapArea.h"
#import <objc/runtime.h>

2.定义全局变量,用其地址作为关联对象的key

static char kTopNameKey;
static char kRightNameKey;
static char kButtomNameKey;
static char kLeftNameKey;

3.设置关联对象

- (void)addIncreaseTapAreaWithTop:(CGFloat)top buttom:(CGFloat)buttom left:(CGFloat)left right:(CGFloat)right {

    objc_setAssociatedObject(self, &kTopNameKey, [NSNumber numberWithFloat:top], OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, &kRightNameKey, [NSNumber numberWithFloat:right], OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, &kButtomNameKey, [NSNumber numberWithFloat:buttom], OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, &kLeftNameKey, [NSNumber numberWithFloat:left], OBJC_ASSOCIATION_COPY_NONATOMIC);

}

objc_setAssociatedObject(<#id object#>, <#const void *key#>, <#id value#>, <#objc_AssociationPolicy policy#>)的四个参数:
1).需要关联对象的对象,在这里是UIButton类的对象,即self。

2).关联对象的key的地址,个人理解类似于定义属性时的属性名,在获取时会根据这个唯一地址取值。

3).id value 即关联对象,类似于属性值。

4).关联策略,有以下几种策略:

 /**
     * Policies related to associative references.
     * These are options to objc_setAssociatedObject()
     */
    typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
        OBJC_ASSOCIATION_ASSIGN = 0,
        OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,
        OBJC_ASSOCIATION_COPY_NONATOMIC = 3,
        OBJC_ASSOCIATION_RETAIN = 01401,
        OBJC_ASSOCIATION_COPY = 01403
    };

这些跟@property语法中的选项一个意思

4.在该API中返回扩大点击范围后的rect

- (CGRect)IncreaseAreaRect
{
    NSNumber *top = objc_getAssociatedObject(self, &kTopNameKey);
    NSNumber *right = objc_getAssociatedObject(self, &kRightNameKey);
    NSNumber *buttom = objc_getAssociatedObject(self, &kButtomNameKey);
    NSNumber *left = objc_getAssociatedObject(self, &kLeftNameKey);
    if (top && right && buttom && left)
    {
        return CGRectMake(self.bounds.origin.x - left.floatValue,
                          self.bounds.origin.y - top.floatValue,
                          self.bounds.size.width + left.floatValue + right.floatValue,
                          self.bounds.size.height + top.floatValue + buttom.floatValue);
    }
    else
    {
        return self.bounds;
    }
}

objc_getAssociatedObject(<#id object#>, <#const void *key#>)
该方法是通过先前定义的唯一key地址获取到该地址对应的value。

5.根据扩大后的rect,在hitTest方法中返回该rect(对hitTest方法不理解的请移步hitTest详解

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
    CGRect rect = [self IncreaseAreaRect];
    if (CGRectEqualToRect(rect, self.bounds))
    {
        return [super hitTest:point withEvent:event];
    }
    return CGRectContainsPoint(rect, point) ? self : nil;
}

到这里我们给按钮扩大点击范围就已经完成了,接下来,只要在需要的地方导入该头文件,button对象调用该方法,传入你希望扩大的范围值就可以了。
其实,这只是runtime动态关联对象很简单的一个例子,相信大家从这个例子可以发散出很多技巧,更快捷,有效的完成开发。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值