美文网首页
runtime - 关联属性

runtime - 关联属性

作者: 啊啊啊啊锋 | 来源:发表于2016-07-05 15:52 被阅读68次

我们知道苹果不允许我们自己给已经存在的类通过分类添加方法的,
但是有时候我们确实需要给某个类从而分类添加属性,那么我们该怎么办呢?
通过这一节学习,我们也许就会有思路了!

为了引出今天要学习的东西,假设我们的项目有这样一个需求,我们要给所有继承自NSObjct的类增加一个objName的属性,而且这个属性必须卸载分类里边,好了那么在我们还不是太了解runtime的情况下,我们可能会这么做:
新建一个NSObjct的分类,命名为ObjConnect,在.h文件里边,我们声明一个属性:

/** 我么知道如果我们给自定义的分类增加了某个属性是没问题的,但是如果是给某个分类增加一个属性那么会有什么问题呢?
 *  在这里我们只在NSObjct的分类里边增加一个objName的属性,而不做任何其他事情,那么我们看看会有什么问题 
 */
@property (nonatomic, copy) NSString *objName;

然后我们再新建一个Dog类,继承自NSObjct,除此之外我们不做任何其他事情。

在我们的控制器里边,初始化一个Dog对象,然后给objName初始化一个值并打印之,代码如下:

Dog *dog = [Dog new];
dog.objName = @"旺财";
NSLog(@"%@", dog.objName);

好了,让我们运行程序:

2016-07-05 14:44:06.699 ZFRuntime[1314:135570] -[Dog setObjName:]: unrecognized selector sent to instance 0x7fbed341c7b0
2016-07-05 14:44:06.703 ZFRuntime[1314:135570] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Dog setObjName:]: unrecognized selector sent to instance 0x7fbed341c7b0'

这时候我们看到程序崩溃了,并且控制台输出了如上的错误,提示[Dog setObjName:]这个方法系统并不认识,因为程序不允许我们给分类添加这样的属性。

下边我们在思考,既然提示[Dog setObjName:]这个方法认识,那么我们自己写objName的setget方法行不行呢?按照这个思路我们再来试一下,在NSObjct这个分类里边增如下几行代码:

/** 我们看看自己来写`objName`的`set`和`get`方法 */
- (void)setObjName:(NSString *)objName
{
    self.objName = objName;
}

- (NSString *)objName
{
    return self.objName;
}

然后我们再次运行程序:这个时候程序出现了一个更严重的问题,提示内存出现泄漏,看来这样也打不到我们的目的。

既然上边两个思路都行不通,那么让我们用运行时的方式看看能不能解决这个问题呢?

首先在NSObjct分类的.m文件里边定义一个关联值:

/** 系统将会通过这个关联值来获取属性值,注意必须保证这个值唯一,通常使用`static const void *`方式来声明 */
static const void *TagSetObjNameKey;

然后实现在两个方法:

/** 设置关联的值,也就是设置`objName`属性的值,可以理解为这个属性的`setter`方法 */
- (void)setObjName:(NSString *)objName
{
    objc_setAssociatedObject(self, TagSetObjNameKey, objName, OBJC_ASSOCIATION_COPY);
}

/** 获取关联的值,也就是获取`objName`,可以理解为这个属性的`getter`方法 */
- (NSString *)objName
{
    return objc_getAssociatedObject(self, TagSetObjNameKey);
}

好了让我们再次运行程序,这是口可以看到控制台打印信息:

2016-07-05 15:01:26.036 ZFRuntime[1424:145877] 旺财

说明我们的目的已经实现了,通过runtime的方法,我们成功地给分类增加了一个属性!

既然运行时的这个API这么方便,那么再来分析下这几个方法到底什么意思,我们以后要是使用的话应该传递什么参数呢?

苹果官方文档里边,和属性关联相关的API有三个,这三个API分别是:

/**
*  定义:通过给定关联的`类`和`关联策略`等,为某个类增加关联(属性)
*
*  @param object 要关联的(要增加属性的)那个类
*  @param key    关联的键,例如上边例子中我们传递的是 `TagSetObjNameKey`
*  @param value  通过`键`要关联的那个值,我们简单可以理解为我们自定义的这个属性。(如果要清除某个关联,这个值可以设置为nil,但是很少这么做)
*  @param policy 关联策略(关于这个参数下边我们会详解)
*/
void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy)

/**
*  定义:通过给定`类`和`关联键`获取关联(属性)
*
*  @param object 同上
*  @param key    同上
*
*  @return 关联的值(属性)
*/
id objc_getAssociatedObject(id object, void *key)

/**
*  定义:给定关联的`类`,移除所有关联(这个方法)
*  备注:这个方法很少用
*  @param object 同上
*/
void objc_removeAssociatedObjects(id object)

这里有几点我们有必要说明一下:

  • 关于void objc_setAssociatedObjectobjc_getAssociatedObjectvoid *key这个参数,其实这个参数有很多种写法,比较常见的有以下几种:

    • 示例程序中的写法,即 static const void *关联键;,这中写法在SDWebImage中比较常见
    • _cmd的方式(_cmd代表本方法的名称),关于这个东西可以参考这里,笔者第一次见到这个用法是在这个demo里边
    • 还有一种方法是@selector(方法名)的方式
      其实这几种写法都大同小异,根据个人爱好来就可以了
  • 关于objc_setAssociatedObject方法中objc_AssociationPolicy policy这个参数,苹果官方是这样定义的,简单理解就是引用方式,相当于我们在声明属性是()里边写的那几个东西:

      enum {
          OBJC_ASSOCIATION_ASSIGN = 0, // (assign)
          OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, (retain, nonactomic)
          OBJC_ASSOCIATION_COPY_NONATOMIC = 3, (copy, nonactomic)
          OBJC_ASSOCIATION_RETAIN = 01401, (retain)
          OBJC_ASSOCIATION_COPY = 01403 (copy)
      };

相关文章

  • Runtime总结

    参考: Objc Runtime 总结runtime 一, runtime 关联属性 1,设置关联值 object...

  • runtime关联属性

    前言 在开发中经常需要给已有的类添加方法和属性,但是Objective-C是不允许给已有类通过分类添加属性的,因为...

  • runtime - 关联属性

    我们知道苹果不允许我们自己给已经存在的类通过分类添加方法的,但是有时候我们确实需要给某个类从而分类添加属性,那么我...

  • runtime关联属性

    类别是开发中常常使用的东西,但是偶尔需要添加属性,这个就需要使用继承来实现,但是如果是只有一两个属性的话,也太过麻...

  • Runtime 关联对象, 可在分类中添加属性

    Runtime 关联对象, 可在分类中添加属性 关联 API 如下 设置关联值 获取关联值 取消关联 关联策略

  • iOS关联对象技术原理

    iOS 通过 runtime 的 API 可以给分类添加属性,关联属性总共有下边3个 API 通过 runtime...

  • 为什么使用Runtime又可以添加属性?

    使用Runtime技术中的关联对象可以为类别添加属性。其原因是:关联对象都由AssociationsManager...

  • 浅谈runtime关联

    浅谈runtime关联 浅谈runtime关联

  • Objective-C Runtime: 变量和属性

    本文只是整理Runtime中,成员变量、属性、关联对象、方法交换使用实例。不会很细致的讲解Runtime的内容,如...

  • 如何实现分类中添加弱引用属性

    需求: 实现分类中添加弱引用属性 众所周知runtime中关联属性的几种类型如下: 但如果想实现弱引用的关联对象就...

网友评论

      本文标题:runtime - 关联属性

      本文链接:https://www.haomeiwen.com/subject/huihjttx.html