美文网首页
问题:@protocol 和 category 中如何使用 @p

问题:@protocol 和 category 中如何使用 @p

作者: 姜小舟 | 来源:发表于2020-05-07 16:09 被阅读0次
    • 在 protocol 中使用 property 只会生成 setter 和 getter 方法声明,我们使用属性的目的,是希望遵守我协议的对象能实现该属性。

    • 在 category 中增加属性的目的主要为了解耦,在很多第三方框架中会使用。在 category 中使用 @property 只会生成 setter 和 getter 方法的声明,并不会自动生成实例变量以及存取方法,Xcode 会警告需要手动实现 setter 和 getter 方法。为什么这样呢?这是因为 category 它是在运行时决定的。在编译时,对象的内存布局已经确定,如果添加实例变量就会破坏类的内部布局,这对编译型语言来说是灾难性的。所以一般使用 runtime 中的关联对象为已经存在的类添加属性。关联对象类似于成员变量,不过是在运行时添加的。在 runtime 中所有的关联对象都由 AssociationsManager 管理。AssociationsManager 里面是由一个静态 AssociationsHashMap 来存储所有的关联对象的。这相当于把所有对象的关联对象都存在一个全局 map 里面。而 map 的 key 是这个对象的指针地址(任意两个不同对象的指针地址一定是不同的),而这个 map 的 value 又是另外一个 AssociationsHashMap,里面保存了关联对象的 KV 对。runtime 的销毁对象函数 objc_destructInstance里面会判断这个对象有没有关联对象,如果有,会调用 _object_remove_assocations 做关联对象的清理工作。如果我们真的需要给 category 增加属性的实现,需要借助于运行时的两个函数:
      objc_setAssociatedObject
      objc_getAssociatedObject

      示例:

      // MyView+MyCategory.h
      #import "MyView.h"
      
      @interface MyView (MyCategory)
      // 在 Category 中定义属性:
      @property (assign, nonatomic) int32_t viewIndex;
      @end
      
      // MyView+MyCategory.m
      #import "MyView+MyCategory.h"
      #import <objc/runtime.h>
      
      // 标记属性的 Key:
      static const void *ViewIndexKey = &ViewIndexKey;
      
      @implementation MyView (MyCategory)
      
      @dynamic viewIndex;
      
      - (void)setViewIndex:(int32_t)viewIndex {
          objc_setAssociatedObject(self, ViewIndexKey, @(viewIndex), OBJC_ASSOCIATION_ASSIGN);
      }
      
      - (int32_t)viewIndex {
          return [objc_getAssociatedObject(self, ViewIndexKey) intValue];
      }
      @end
      

    相关文章

      网友评论

          本文标题:问题:@protocol 和 category 中如何使用 @p

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