美文网首页
iOS之关联对象

iOS之关联对象

作者: 賣女孩的小火柴 | 来源:发表于2020-11-17 14:26 被阅读0次

            我们在 iOS 开发中经常需要使用分类(Category),为已经存在的类添加属性的需求,但是使用@property 并不能在分类中正确创建实例变量和存取方法。

            不过,通过 Objective-C 运行时中的关联对象,也就是 Associated Object,我们可以实现上述需求。

    分类中的 @property :@property 可以说是一个 Objective-C 编程中的“宏”,它有元编程的思想。

    @interface Object : NSObject

    @property (nonatomic, strong) NSString *property;

    @end

    在使用上述代码时会做三件事:

        1.生成实例变量 _property

        2.生成 getter 方法 - property

        3.生成 setter 方法 - setProperty:

    @implementation Object{

    NSString *_property;

    }

    - (NSString *)property {

    return _property;

    }

    - (void)setProperty:(NSString *)property {

    _property = property;

    }

    @end

            这些代码都是编译器为我们生成的,虽然你看不到它,但是它确实在这里,我们既然可以在类中使用。但分类中的 @property 并没有为我们生成实例变量以及存取方法,而需要我们手动实现。

    使用关联对象

    Q:我们为什么要使用关联对象?

    A:因为在分类中 @property 并不会自动生成实例变量以及存取方法,所以一般使用关联对象为已经存在的类添加"属性"

    下面,会介绍 ObjC 运行时为我们提供的与关联对象有关的 API,并在分类中实现一个伪属性

    NSObject+AssociatedObject.h

    @interface NSObject (AssociatedObject)

    @property (nonatomic, strong) id associatedObject;

    @end

    NSObject+AssociatedObject.m

    @implementation NSObject (AssociatedObject)

    - (void)setAssociatedObject:(id)object {

    objc_setAssociatedObject(self, @selector(associatedObject), object, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    }

    - (id)associatedObject {

    return objc_getAssociatedObject(self,  _cmd);

    }

    注:这里的 _cmd 代指当前方法的选择子,也就是 @selector(categoryProperty)。

    我们使用了两个方法 objc_getAssociatedObject 以及 objc_setAssociatedObject 来模拟“属性"的存取方法,而使用关联对象模拟实例变量。

    在这里需要解释下我们为什么会向方法中传入 @selector(categoryProperty)?

    关于上面这个问题,我们须得看下方法的原型:

    id objc_getAssociatedObject(id object, const void *key);

    void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);

            从上面的方法原型中我们可以看出@selector(categoryProperty) 也就是参数中的 key,其实可以使用静态指针 static void * 类型的参数来代替,不过在这里,还是强烈推荐使用 @selector(categoryProperty) 作为 key 传入。因为这种方法省略了声明参数的代码,并且能很好地保证 key 的唯一性。(当然也避免了起名不会起的原因)

    下来需要解释的一个就是OBJC_ASSOCIATION_RETAIN_NONATOMIC

    关联对象的行为

    而我们在代码中实现的属性 associatedObject 就相当于使用了 nonatomic 和 strong 修饰符。

    说到上面2个方法一个设置和一个获取,那么哪有一个删除objc_removeAssociatedObjects

            你可能会在刚开始接触对象关联时想要尝试去调用objc_removeAssociatedObjects() 来进行删除操作,但如文档中所述,你不应该自己手动调用这个函数。此函数的主要目的是在“初试状态”时方便地返回一个对象。你不应该用这个函数来删除对象的属性,因为可能会导致其他客户对其添加的属性也被移除了。规范的方法是:调用objc_setAssociatedObject方法并传入一个nil 值来清除一个关联。

    应用:

    添加私有属性用于更好地去实现细节。当扩展一个内建类的行为时,保持附加属性的状态可能非常必要。

    添加public属性来增强category的功能。有些情况下这种(通过关联对象)让category行为更灵活的做法比在用一个带变量的方法来实现更有意义。

    创建一个用于KVO的关联观察者。当在一个category的实现中使用KVO时,建议用一个自定义的关联对象而不是该对象本身作观察者。


    相关文章

      网友评论

          本文标题:iOS之关联对象

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