iOS 底层学习9 -- 分类关联对象原理


@property 自动帮我们做的三件事
第一件事情:生成一个带下划线的成员变量
第二件事情:声明一个set方法,一个get方法
第三件事情:生成set方法和get方法的具体实现



分类中声明属性,系统只会帮我们做一件事件,就是声明set方法和get方法,就没了。
我们不能直接给分类添加成员变量,但是可以间接现实分类有成员变量的效果



通过全局字典给分类添加类似属性的效果有很多点缺陷:比如
1.会存在内存泄露问题
2.会存在线程安全问题
设置关联对象:(Associated -- 关联的)
objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,
id _Nullable value, objc_AssociationPolicy policy)

id _Nonnull object -- 对象,也就是说给哪个对象添加关联对象。
id _Nullable value -- 就是要关联的值
objc_AssociationPolicy policy -- 关联策略 (Policy -- 策略)



nonatomic -- 非线程安全;
获取关联对象:
objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key)
总的来说:可以理解为把value用key存起来,类似字典

上图中的写法还是存在一些问题的。
static const void *MJNameKey = &MJNameKey
只要给全局变量加上了static,意味着这个全局变量的作用域仅限于当前文件(也就是仅限于MJPerson+Test.m这个文件)
const void * _Nonnull key需要传地址值, int p , &p就是p的地址值


我们定义的key前面加const是为了匹配,而且key根本不需要赋值,我们要的不是key里面存储的值,要的是key的地址值,所以我们只要定义下这个key就好了。

@“name”这种直接写出来的字符串是放在数据常量区的,也就是说这个@“name”不管写上多少次其内存地址都是不变的。



@selector(name),不管写多少次,只要传进去的方法名字是一样的,@selector(name)的地址值就是一样的(底层@selector返回的是某个结构体的指针)



  • (NSString *)name:(id)self _cmd:(SEL)_cmd
    self和_cmd 是隐式参数 在- (NSString *)name { }中写的_cmd. _cmd == @selector(name)
    _cmd代表你当前方法的@selector
  • (void)setName:(NString *)name { }中写的_cmd . _cmd == @selector(setName:)
    关联对象,设置value的key跟取value的key必须保持一致

我们使用objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,
id _Nullable value, objc_AssociationPolicy policy)给分类传进去的value值,不是当作成员变量那样赛到person对象里面去的。它是分开存储的。也就是加的这个value是不会影响我们原来类对象的结构的,也不会影响到我们person实例对象在内存中的结构。



上图person对象在内存中就只有一个isa,一个_age.也就是说通过objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,
id _Nullable value, objc_AssociationPolicy policy)给person分类添加的类似于属性的值,不是存储在person类对象,也不是存储在perosn实例对象里面,而是存储在其他地方。
HashMap对应oc中的字典。




DISGUISE(object)可以理解为拿到实例对象的地址。
所以关联对象是runtime自己维护了一个全局的AssociationsManager(也就是 *_map)

如果key对应的value为nil,也就是key对应的value为空



key对应的键值对就会被移除
AssociationsMap中存的一对一对的 viod * ObjectAssociation


运行上图会出现坏内存访问,也可以理解野也指针访问。

也就是说tempPerson销毁之后,上图中的value还存有tempPerson的地址值,这个时候再去访问已经销毁的tempPerson对象,就会发生坏内存访问。这也就说明了value这个东西不是弱引用,也就是不是weak修饰的。如果它是弱引用weak的话,相当于我这个person对象销毁之后,会把value置为nil。但是value并没有置为nil,所以value没有达到弱引用的效果。

使用什么关联策略,就跟我们平时用什么关键词修饰属性一样的道理。
关联策略就相当于将来你要保存传进来的值使用什么策略,就好比平时我们写属性的时候,会写strong /copy/weak.那这样就决定了,将来你这个属性,以怎样的内存管理方式去管理它
字符串我们一般用copy



既然我们外面声明用copy,那么我们希望内部也来个copy策略。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354