美文网首页
Category 拾遗

Category 拾遗

作者: 化二缺 | 来源:发表于2020-05-08 09:56 被阅读0次

Category结构体

每创建一个分类都会创建一个分类结构体

struct _category_t {
   const char *name;
   classref_t cls;
   struct method_list_t *instanceMethods; //对象方法
   struct method_list_t *classMethods; //类方法
   struct protocol_list_t * protocols;//协议
   struct prop_list_t * instanceProperties; //属性
   struct property_list_t * _classProperties;
   ...
  
};

方法覆盖

  • 分类会覆盖原有的方法
  • 这个覆盖不是真的覆盖,是优先调用而已,因为在编译合并方法的时候底层的方法会把分类的方法放在前面,原来类的方法放到后面,重新组成方法数组,所以如果分类含有和原来的类相同名字的方法优先找到的就是分类的方法,不再继续往后找了。方法还在。
  • memove 内存移动 memcpy 内存拷贝

Category 的实现原理

  • Category编译之后的底层结构是 struct category_t 里面存储分类的对象方法,类方法,属性,协议信息
  • 在程序运行的时候,runtime会将Category的数据合并到类信息中

Category和 Class Extension(OC)的区别是什么?

Class Extension在编译的时候它的数据就已经包含在类信息中
Category是在运行时,才会将数据合并到类信息中

Category中有load方法么?load方法什么时候调用?load方法能继承么?

  • runtime加载的时候就会调用, 是用地址直接调用的不是用发消息调用的
  • 每个类、分类都的+load 在程序运行过程中只调用一次
  • zjps:不要写一些不必要的load 方法,不然会严重影响启动速度
  • 1.先调用类的+load ,按照编译先后顺序调用,调用子类的+load之前会先调用父类的+load ,所以能继承,继承时,先调用父类的load
  • 2.再调用分类的+load 按照编译的先后顺序调用
  • image.png

load, initialize方法区别是什么?他们在category中的调用顺序是什么?以及继承是他们之间的调用顺序?

  • initialize 是在类第一次接收到消息的时候调用
  • 调用顺序是
  • 先调用父类的+initialize,再调用子类的 +initialize (每个类只会初始化一次)
  • initialize 和 load 的很大区别是 ,initialize是通过objc_msgSend进行调用的,所有会有以下特点
  • 1.如果子类没有实现 initialize 会调用父类的initialize (多以父类的initialize可能调用多次)
  • 2.如果分类实现了initialize,就覆盖类本身的initialize调用

1.先调用类的load

  • a. 先编译的类,优先调用load
  • b.调用子类的load之前 会调用父类的load

2.在调用分类的load

  • a.先编译的分类,优先调用load

在调用initialize

  • a.先初始化父类
  • b.再初始化子类(可能最终调用的是父类)

Category能否添加成员变量?如果可以,如何Category添加成员变量?

  • 不能直接添加成员变量,但是可以间接实现
  • 使用关联对象的方式

关联对象

  • swift

UIimage + AlamofireImage.swift 源码

private struct AssociatedKey {
        static var inflated = "af_UIImage.Inflated"
  }
。。。。。。
 /// Returns whether the image is inflated.
    public var af_inflated: Bool {
        get {
            if let inflated = objc_getAssociatedObject(self, &AssociatedKey.inflated) as? Bool {
                return inflated
            } else {
                return false
            }
        }
        set {
            objc_setAssociatedObject(self, &AssociatedKey.inflated, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
  • OC
@property(copy,nonatomic) NSString * Jname;
。。。。。。
static const char JnameKey;
-(void)setJname:(NSString *)Jname{
   objc_setAssociatedObject(self,&JnameKey, Jname, OBJC_ASSOCIATION_COPY);
}

-(NSString *)Jname{
   return objc_getAssociatedObject(self, &JnameKey);
}

或者

-(void)setJname:(NSString *)Jname{
   objc_setAssociatedObject(self,@"Jname", Jname, OBJC_ASSOCIATION_COPY);
}

-(NSString *)Jname{
   return objc_getAssociatedObject(self, @"Jname");
}

或者

-(void)setJname:(NSString *)Jname{
   // _cmd ==  @selector(setJname)
   objc_setAssociatedObject(self,@selector(Jname), Jname, OBJC_ASSOCIATION_COPY);
}

-(NSString *)Jname{
  // _cmd ==  @selector(Jname)
   return objc_getAssociatedObject(self, @selector(Jname));
}

关联对象的底层

  • 实现关联对象技术的核心对象有
  • AssociationsManager
  • AssociationsHashMap
  • ObjectAssociationMap
  • ObjcAssociation
  • 关联对象不是存在实例对象和类对象的内存里 而是在 AssociationsManager 里
image.png

相关文章

网友评论

      本文标题:Category 拾遗

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