objc_setAssociatedObject、objc_getAssociatedObject、objc_removeAssociatedObjects

一 关联的3个方法

  • objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
/**
 *  关联你需要关联的对象
 *
 *  @param object   调用我的类,常见的是self
 *  @param key      一个关联的key值。有点类似,字典的key和广播的Name
 *  @param value    关联的对象  特别:设置成nil,则表示删除该对象的某一个扩展属性
 *  @param policy   关联的方式  OBJC_ASSOCIATION_RETAIN_NONATOMIC 等
 */
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
  • objc_getAssociatedObject(id object, void *key)
/**
 *  获取关联的对象
 *
 *  @param object 调用我的类,常见的是self
 *  @param key    一个关联的key值。有点类似,字典的key和广播的Name
 */
objc_getAssociatedObject(id object, void *key)
  • objc_removeAssociatedObjects(id object)
/**
 *  打断对象的所有关联
 *
 *  @param object 要删除关联的对象,常见的是self
 */
objc_removeAssociatedObjects(id object)

tips: 使用objc_setAssociatedObject等,需要引入头文件 #import objc/runtime.h

二 关联的主要作用是扩展属性。

  • 主要作用是当属性和全局变量不能使用的时候进行扩展属性,说白了就是在我配合category会更好的效果,为什么?因为使用时需要key值,一般是一个不可变的字符串,如果在一类中大量的调用我会产生很多不同的key值,这样不便于维护

  • 类别是不可以添加属性的。平常看到在 category 中 写了 @property 实际是生成2个方法罢了

三 应用:

3.1. 用UIAlertview来示例关联与方法交换

如果要给UIAlertview加上一个block 的点击事件,一般的做法是重写UIAlertview,在子类中加上点击的block。这样耦合度太高了,如果我们能够写一个category实现alertview的点击block 就好了,但是category是不允许属性的,所以我们得用另外一种方式实“现曲线救国”。

//UIAlertView+Associate.h
#import <UIKit/UIKit.h>
typedef void (^bSuccessBlock)(NSInteger buttonIndex);
@interface UIAlertView (Associate)<UIAlertViewDelegate>
-(void)showWithBlock:(bSuccessBlock)block;
@end
//UIAlertView+Associate.m
#import "UIAlertView+Associate.h"
#import <objc/runtime.h>
static const char alertKey;
@implementation UIAlertView (Associate)
-(void)showWithBlock:(bSuccessBlock)block{
    if (block) {
        objc_setAssociatedObject(self, &alertKey, block, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        self.delegate = self;
    }
    [self show];
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    bSuccessBlock block = objc_getAssociatedObject(self, &alertKey);
    block(buttonIndex);
}
@end

使用

 UIAlertView *tAlertView = [[UIAlertView alloc]initWithTitle:@"me" message:@"" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"其他", nil];
   [tAlertView showWithBlock:^(NSInteger buttonIndex) {
       NSLog(@"%ld",(long)buttonIndex);
   }];

拓展

1 @property 的本质是什么?ivar、getter、setter 是如何生成并添加到这个类中的?

“属性” (property)作为 Objective-C 的一项特性,主要的作用就在于封装对象中的数据。Objective-C 对象通常会把其所需要的数据保存为各种实例变量。实例变量一般通过“存取方法”(access method)来访问。其中,“获取方法” (getter)用于读取变量值,而“设置方法” (setter)用于写入变量值。

1.1 @property 的本质是什么?

@property =ivar(实例变量)+access method (存取方法= getter + setter);

@interface Person : NSObject
@property NSString *firstName;
@property NSString *lastName;
@end
//相当于下边,生成生成存取方法+实例变量
@interface Person : NSObject
    NSString *_firstName;
    NSString *_lastName;
}
- (NSString *)firstName;
- (void)setFirstName:(NSString *)firstName;
- (NSString *)lastName;
- (void)setLastName:(NSString *)lastName;
@end
1.2 ivar、getter、setter 是如何生成并添加到这个类中的?

“自动合成”( autosynthesis):完成属性定义后,编译器会自动编写访问这些属性所需的方法。
这个过程由编译器在编译期执行,所以编辑器里看不到这些“合成方法”(synthesized method)的源代码。

//属性定义后会自动生成两个实例变量,其名称分别为 _firstName 与 _lastName
@interface Person : NSObject
@property NSString *firstName;
@property NSString *lastName;
@end
//或者
//也可以通过 @synthesize 语法来指定实例变量的名字.
@implementation Person
@synthesize firstName = _myFirstName;
@synthesize lastName = _myLastName;
@end
1.3 属性是怎么实现的
  • OBJC_IVAR_类名$属性名称 :该属性的“偏移量” (offset),这个偏移量是“硬编码” (hardcode),表示该变量距离存放对象的内存区域的起始地址有多远。
  • setter 与 getter 方法对应的实现函数
  • ivar_list :成员变量列表
  • method_list :方法列表
  • prop_list :属性列表

也就是说我们每次在增加一个属性:
(1)系统都会在 ivar_list 中添加一个成员变量的描述,
(2)在 method_list 中增加 setter 与 getter 方法的描述,
(3)在prop_list 中增加一个属性的描述,
(4)然后计算该属性在对象中的偏移量,
(5)然后给出 setter 与 getter 方法对应的实现,
(6)在 setter 方法中从偏移量的位置开始赋值,在 getter 方法中从偏移量开始取值,为了能够读取正确字节数,系统对象偏移量的指针类型进行了类型强转.
1.4 @protocol 和 category 中如何使用 @property

  • 在 protocol 中使用 property 只会生成 setter 和 getter 方法声明,我们使用属性的目的,是希望遵守我协议的对象能实现该属性
  • category 使用 @property 也是只会生成 setter 和 getter 方法的声明,如果我们真的需要给 category 增加属性的实现,需要借助于运行时的两个函数:
    • objc_setAssociatedObject
    • objc_getAssociatedObject

1.[Objective-c 高阶语法] 关联与方法交换
2.ios设计模式
3.@property 的本质是什么?
4.iOS Category中添加属性和成员变量的区别
5.Objective-C类成员变量深度剖析
6.让我们来谈谈 @property

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值