美文网首页
iOS 分类 category(一)

iOS 分类 category(一)

作者: 萨缪 | 来源:发表于2020-04-27 22:35 被阅读0次

    今天要做的事有很多呢

    Category是Objective-C 2.0之后添加的语言特性,分类、类别其实都是指的Category。Category的主要作用是为已经存在的类添加方法。
    Objective-C 中的 Category 就是对装饰模式的一种具体实现。它的主要作用是在不改变原有类的前提下,动态地给这个类添加一些方法。
    分类优点

    声明私有方法
    分解体积庞大的类文件
    把Framework私有方法公开
    模拟多继承(另外可以模拟多继承的还有protocol)

    Category源码:
    Category 是表示一个指向分类的结构体的指针,其定义如下:

    typedef struct objc_category *Category;
    struct objc_category {
    char *category_name OBJC2_UNAVAILABLE; // 分类名
    char *class_name OBJC2_UNAVAILABLE; // 分类所属的类名
    struct objc_method_list *instance_methods OBJC2_UNAVAILABLE; // 实例方法列表
    struct objc_method_list *class_methods OBJC2_UNAVAILABLE; // 类方法列表
    struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 分类所实现的协议列表
    }

    结构体主要包含了分类定义的实例方法与类方法,其中instance_methods 列表是 objc_class 中方法列表的一个子集,而class_methods列表是元类方法列表的一个子集。
    实现原理

    1.我们不主动引入 Category 的头文件,Category 中的方法都会被添加进主类中。我们可以通过 - performSelector: 等方式对 Category 中的相应方法进行调用:
    a)将 Category 和它的主类(或元类)注册到哈希表中;
    b)如果主类(或元类)已实现,那么重建它的方法列表。
    
    2.在这里分了两种情况进行处理:
    a)Category 中的实例方法和属性被整合到主类中;
    b)类方法则被整合到元类中
    c)对协议的处理比较特殊,Category 中的协议被同时整合到了主类和元类中。
    
    3.最终都是通过调用 staticvoid remethodizeClass(Class cls) 函数来重新整理类的数据的。
    

    分类特点

    1.分类是用于给原有类添加方法的,因为分类的结构体指针中,没有属性列表,只有方法列表。原则上讲它只能添加方法, 不能添加属性(成员变量),实际上可以通过其它方式添加属性 ;
    
    2.分类中的可以写@property, 但不会生成setter/getter方法, 也不会生成实现以及私有的成员变量,会编译通过,但是引用变量会报错;
    
    3.如果分类中有和原有类同名的方法, 会优先调用分类中的方法, 就是说会忽略原有类的方法,同名方法调用的优先级为 分类 > 本类 > 父类;
    
    4.如果多个分类中都有和原有类中同名的方法, 那么调用该方法的时候执行谁由编译器决定;编译器会执行最后一个参与编译的分类中的方法。
    
    5.运行时决议
    
    6.同名分类方法生效取决于编译顺序
    
    7.名字相同的分类会引起编译报错
    

    在分类中,给分类添加成员变量实际上是添加属性:

    示例代码

    import <objc/runtime.h>

    /* ---------------.h---------------*/
    @interface NSString (url)
    @property (nonatomic, retain) NSString *url;
    @end

    /* ---------------.m---------------*/
    static char imageURLKey;
    @implementation NSString (url)

    • (void)setUrl:(NSString *)url
      {
      objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
      }

    • (NSString *)url
      {
      return objc_getAssociatedObject(self, &imageURLKey);
      }
      @end

    objc_getAssociatedObject

    这个函数先根据对象地址在 AssociationsHashMap 中查找其对应的 ObjectAssociationMap 对象,如果能找到则进一步根据 key 在 ObjectAssociationMap 对象中查找这个 key 所对应的关联结构 ObjcAssociation ,如果能找到则返回 ObjcAssociation 对象的 value 值,否则返回 nil;
    
    objc_getAssociatedObject有两个参数,第一个参数为从该object中获取关联对象,第二个参数为想要获取关联对象的key;
    

    /**

    • Returns the value associated with a given object for a given key.
    • @param object The source object for the association.
    • @param key The key for the association.
    • @return The value associated with the key \e key for \e object.
    • @see objc_setAssociatedObject
      */
      OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
      OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);

    objc_setAssociatedObject

    参数说明:

    object和key同于objc_getAssociatedObject;
    
    value:需要和object建立关联引用对象的value;
    
    policy:关联策略,等同于给property添加关键字
    

    /**

    • Sets an associated value for a given object using a given key and association policy.
    • @param object The source object for the association.
    • @param key The key for the association.
    • @param value The value to associate with the key key for object. Pass nil to clear an existing association.
    • @param policy The policy for the association. For possible values, see “Associative Object Behaviors.”
    • @see objc_setAssociatedObject
    • @see objc_removeAssociatedObjects
      */
      OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
      OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);

    与分类相似的还有一个扩展:
    扩展

    声明私有属性
    
    声明私有方法
    
    声明私有成员变量
    
    编译时决议
    
    只以声明存在,寄生于宿主类.m中
    
    不能为系统类添加扩展
    

    类扩展优缺点分析

    ① 类扩展的属性和方法都是私有的,也可以定义在.h中,这样就是共有的,类扩展中的方法是一定要实现的方法。Category没有这个限制。
    分类、扩展区别

    category、extension异同点分析
    1、分类(category)
    ① category只能添加“方法”,不能添加成员变量。
    ② 分类中可以访问原来类中的成员变量,但是只能访问@protect和@public属性。
    ③ 添加方法加上前缀,添加方法会覆盖父类的同名方法,可以防止意外覆盖,也防止被别人覆盖。
    ④ 分类中添加的成员变量,要通过getter、setter方法进行添加。

    类扩展(extension)
    ① 类扩展的属性和方法都是私有的,也可以定义在.h中,这样就是共有的,类扩展中的方法是一定要实现的方法。Category没有这个限制。

    相关文章

      网友评论

          本文标题:iOS 分类 category(一)

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