一、Category与Associative作为objective-c的扩展机制的两个特性。
1.category即类目/分类,可以通过它来扩展方法;
2.associative即关联,可以通过它来扩展属性;
关联是指把两个对象相互关联起来,使得其中的一个对象作为另外一个对象的一部分。
关联特性只有在Mac OS X V10.6以及以后的版本上才是可用的。
在iOS开发中,使用associative,必须使用<objc/runtime.h>的头文件。
在类的定义之外为类增加额外的存储空间
使用关联,我们可以不用修改类的定义而为其对象增加存储空间。这在我们无法访问到类的源码的时候或者是考虑到二进制兼容性的时候是非常有用。
关联是基于关键字的,因此,我们可以为任何对象增加任意多的关联,每个都使用不同的关键字即可。
关联是可以保证被关联的对象在关联对象的整个生命周期都是可用的(在垃圾自动回收环境下也不会导致资源不可回收)。
二、关联
*创建关联(objc_setAssociatedObject)
该函数需要四个参数:源对象,关键字,关联的对象和一个关联策略。
■ object :待扩展的对象实例,
■ key:关键字是一个void类型的指针。每一个关联的关键字必须是唯一的。通常都是会采用静态变量来作为关键字。
■ value:对象实例的属性的值,
■ policy:作为关联的策略,关联策略表明了相关的对象是通过赋值,保留引用还是复制的方式进行关联的;还有这种关联是原子的还是非原子的。这里的关联策略和声明属性时的很类似。策略枚举如下:
<span style="color:#006600;">typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) { OBJC_ASSOCIATION_ASSIGN = 0, /**< Specifies a weak reference to the associated object. */ OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object. * The association is not made atomically. */ OBJC_ASSOCIATION_COPY_NONATOMIC = 3, /**< Specifies that the associated object is copied. * The association is not made atomically. */ OBJC_ASSOCIATION_RETAIN = 01401, /**< Specifies a strong reference to the associated object. * The association is made atomically. */ OBJC_ASSOCIATION_COPY = 01403 /**< Specifies that the associated object is copied. * The association is made atomically. */ };</span>
*获取相关联对象(objc_getAssociatedObject)
*断开关联(objc_removeAssociatedObjects)
objc_removeAssociatedObjects可以断开所有关联。通常情况下不建议使用这个函数,因为他会断开所有关联。只有在需要把对象恢复到“原始状态”的时候才会使用这个函数。断开关联一般是使用objc_setAssociatedObject函数,传入nil值即可。
三、举例:
利用关联进行传值
<span style="color:#666666;">- (void)viewDidLoad { [super viewDidLoad]; UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; [btn setTitle:@"关联" forState:UIControlStateNormal]; [self.view addSubview:btn]; [btn setFrame:CGRectMake(50, 50, 50, 50)]; btn.backgroundColor = [UIColor redColor]; [btn addTarget:self action:@selector(click:) forControlEvents:UIControlEventTouchUpInside]; } -(void)click:(UIButton *)sender { NSString *message = @"你是谁"; UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"提示" message:@"关联传值" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil]; alert.delegate = self; [alert show]; // 即实现了关联传值 objc_setAssociatedObject(alert, @"btn property",sender,OBJC_ASSOCIATION_ASSIGN); } -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { //通过 objc_getAssociatedObject获取关联对象 NSString *messageString =objc_getAssociatedObject(alertView, @"msgstr"); UIButton *sender = objc_getAssociatedObject(alertView, @"btn property"); NSLog(@"%ld",buttonIndex); NSLog(@"%@",messageString); NSLog(@"%@",[[sender titleLabel] text]); }</span>
-------------------------------------------------------------------------------------------------------------------------------
实例间传值 、界面间传值
<span style="color:#666666;">ViewController.m - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor redColor]; } -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSString *message = @"这是一条需要传送的消息"; NSLog(@"%p",message); objc_setAssociatedObject(self.navigationController, @"test", message, OBJC_ASSOCIATION_ASSIGN); Test2ViewController *test2 = [[Test2ViewController alloc] init]; [self.navigationController pushViewController:test2 animated:YES]; } Test2ViewController.m - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. NSString *messageString = objc_getAssociatedObject(self.navigationController, @"test"); self.view.backgroundColor = [UIColor yellowColor]; NSLog(@"%@",messageString); NSLog(@"%@",self.navigationController.viewControllers); NSLog(@"%p",messageString); }</span>
-------------------------------------------------------------------------------------------------------------------------------
类目中动态添加属性
<span style="color:#666666;">UILabel+Associate.h #import <UIKit/UIKit.h> @interface UILabel (Associate) - (void) setFlashColor:(UIColor *) flashColor; - (UIColor *) getFlashColor; @end UILabel+Associate.m #import "UILabel+Associate.h" #import <objc/runtime.h> @implementation UILabel (Associate) static char flashColorKey; - (void) setFlashColor:(UIColor *) flashColor{ objc_setAssociatedObject(self, &flashColorKey, flashColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (UIColor *) getFlashColor{ return objc_getAssociatedObject(self, &flashColorKey); } @end</span>
<span style="color:#666666;">UIAlertView的扩展 .h文件 #import <UIKit/UIKit.h> typedef void (^successBlock)(NSInteger buttonIndex); @interface UIAlertView (Block)<UIAlertViewDelegate> - (void)showWithBlock:(successBlock)block; @end .m文件 #import "UIAlertView+Block.h" #import <objc/runtime.h> static const char alertKey; @implementation UIAlertView (Block) - (void)showWithBlock:(successBlock)block { if (block) { objc_setAssociatedObject(self, &alertKey, block, OBJC_ASSOCIATION_RETAIN_NONATOMIC); self.delegate = self; } [self show]; } - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { successBlock block = objc_getAssociatedObject(self, &alertKey); block(buttonIndex); } @end</span>
<span style="color:#666666;">UIButton的扩展 .h文件 #import <UIKit/UIKit.h> typedef void (^btnBlock)(); @interface UIButton (Block) - (void)handelWithBlock:(btnBlock)block; @end .m文件 #import "UIButton+Block.h" #import <objc/runtime.h> static const char btnKey; @implementation UIButton (Block) - (void)handelWithBlock:(btnBlock)block { if (block) { objc_setAssociatedObject(self, &btnKey, block, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } [self addTarget:self action:@selector(btnAction) forControlEvents:UIControlEventTouchUpInside]; } - (void)btnAction { btnBlock block = objc_getAssociatedObject(self, &btnKey); block(); } @end</span>