日常开发过程中我们经常碰到要给分类添加自定义属性和变量的,下面通过关联对象给分类添加属性,也是runtime的实际应用之一,非常实用。(关于runtime的使用还有很多,这里只简单记录一下利用runtime给分类添加属性)。
关联Runtime提供了下面几个接口:
关联对象
void objc_setAssociatedObject(id object, const void * key, id value, objc_AssociationPolicy policy)
获取关联对象
id objc_getAssociatedObject(id object, const void * key)
移除关联对象
void objc_removeAssociatedObjects(id object)
参数解释:
id object;被关联的对象
const void * key:关联的key,要求唯一
id value:关联的对象
objc_AssociationPolicy policy:内存管理策略
1.给UILabel添加一个 竖直方向的verticalText,如下图所示:
竖直方向的label.png
新建一个继承UILabel的Category,并添加一个成员变量
.h文件
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UILabel (HXVertical)
@property (nonatomic) NSString * verticalText;
@end
NS_ASSUME_NONNULL_END
m.文件
#import "UILabel+HXVertical.h"
#import "objc/Runtime.h"
@implementation UILabel (HXVertical)
- (NSString *)verticalText{
// 获取关联对象
return objc_getAssociatedObject(self, @selector(verticalText));
}
- (void)setVerticalText:(NSString *)verticalText{
//关联对象
objc_setAssociatedObject(self, &verticalText, verticalText, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
NSMutableString *str = [[NSMutableString alloc] initWithString:verticalText];
NSInteger count = str.length;
for (int i = 1; i < count; i ++) {
[str insertString:@"\n" atIndex:i*2-1];
}
self.text = str;
self.numberOfLines = 0;
}
@end
调用时就直接使用点语法:
_textLabel.verticalText = @"厉害了,我的国";
2.给UIButton添加一个扩大点击区域的实例方法
新建一个继承UIButton的Category,并添加一个实例方法
.h文件
#import <UIKit/UIKit.h>
@interface UIButton (HXEnlargeTouchArea)
- (void)setTouchExpandEdgeWithTop:(CGFloat)top right:(CGFloat)right bottom:(CGFloat)bottom left:(CGFloat)left;
@end
.m文件
#import "UIButton+HXEnlargeTouchArea.h"
#import <objc/runtime.h>
@implementation UIButton (HXEnlargeTouchArea)
static char topRegion;
static char rightRegion;
static char bottomRegion;
static char leftRegion;
- (void)setTouchExpandEdgeWithTop:(CGFloat)top right:(CGFloat)right bottom:(CGFloat)bottom left:(CGFloat)left {
//关联对象
objc_setAssociatedObject(self, &topRegion, [NSNumber numberWithFloat:top], OBJC_ASSOCIATION_COPY_NONATOMIC);
objc_setAssociatedObject(self, &rightRegion, [NSNumber numberWithFloat:right], OBJC_ASSOCIATION_COPY_NONATOMIC);
objc_setAssociatedObject(self, &bottomRegion, [NSNumber numberWithFloat:bottom], OBJC_ASSOCIATION_COPY_NONATOMIC);
objc_setAssociatedObject(self, &leftRegion, [NSNumber numberWithFloat:left], OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (CGRect)expandRect
{
//获取关联对象
NSNumber* topEdge = objc_getAssociatedObject(self, &topRegion);
NSNumber* rightEdge = objc_getAssociatedObject(self, &rightRegion);
NSNumber* bottomEdge = objc_getAssociatedObject(self, &bottomRegion);
NSNumber* leftEdge = objc_getAssociatedObject(self, &leftRegion);
if (topEdge && rightEdge && bottomEdge && leftEdge)
{
return CGRectMake(self.bounds.origin.x - leftEdge.floatValue,self.bounds.origin.y - topEdge.floatValue,self.bounds.size.width + leftEdge.floatValue + rightEdge.floatValue,self.bounds.size.height + topEdge.floatValue + bottomEdge.floatValue);
}
else
{
return self.bounds;
}
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
CGRect rect = [self expandRect];
if (CGRectEqualToRect(rect, self.bounds))
{
return [super hitTest:point withEvent:event];
}
return CGRectContainsPoint(rect, point) ? self : nil;
}
@end
创建button并调用:
[button setTouchExpandEdgeWithTop:30 right:30 bottom:30 left:30];
点击button的上下左右各30pt,button也会有响应。