关联(Associative)

本文介绍Objective-C中关联(Associative)和类目(Category)的概念与应用。关联特性允许开发者为类实例动态地添加额外存储空间,无需修改类定义。类目则提供了在不改变原接口的情况下扩展类的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


一、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>








-------------------------------------------------------------------------------------------------------------------------------
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值