美文网首页
iOS category和extension

iOS category和extension

作者: 不会写代码的尬先生 | 来源:发表于2019-06-13 18:06 被阅读0次

    一、category:
    1、分类,可以为一个已知.m文件源码的类添加分类,也可以为只暴露.h文件不知道.m实现的类(系统类)添加分类。
    2、给某个类添加category会生成.h和.m两个文件,文件名为Person+son.h和Person+son.m这种形式,声明和实现部分形如@interface Person (son)和@implementation Person (son),即比普通的类文件多了个括号,括号里是分类的名称
    3、不能添加属性的原因是category是运行时添加,而实例变量是在编译期间添加的,因为属性里也有_ivar实例变量,所以不能添加属性,但是可以通过runtime动态为这个属性设置getter和setter方法,但是这个属性还是没有实例变量的,直接访问_ivar是不可以的。
    4、添加属性编译期间不会报错,runtime时访问会报错(如果添加分类的同时还添加了一个extension,extension添加了同名属性则category添加了这个属性也没问题)
    5、添加原类已有属性是没问题的。
    6、分类添加的方法会放在方法列表的最前面,从而拦截了被分类的原类里的同名方法,如果有两个分类都为一个类重写了同一个方法,会根据这两个分类在xcode文件列表的前后顺序有关,位置靠后的那个分类会拦截这个同名方法。

    例如 有个Person类,他有一个drink方法

    @interface Person : NSObject
    @property (nonatomic,strong) NSString *age;
    - (void)drink;
    
    @end
    
    @implementation Person
    - (void)drink{
        NSLog(@"drink");
    }
    @end
    

    为Person类添加一个分类A,在这个分类的.m文件里重写drink方法

    @implementation Person (A)
    
    - (void)drink{
        NSLog(@"Adrink");
    }
    
    @end
    

    再为Person类添加一个分类B,在这个分类的.m文件里重写drink方法

    @implementation Person (B)
    
    - (void)drink{
        NSLog(@"Bdrink");
    }
    
    @end
    

    那么当我们调用drink方法时会调用哪个类的呢?

        Person *p = [Person new];
        [p drink];
    

    结果是打印分类B的drink方法


    打印

    可以看一下A和B在文件目录中的位置1


    位置.png
    再看一下A和B在文件目录中的位置2
    位置

    这是因为A的位置在B的前面,在编译阶段A被先加载,到了runtime时A的drink方法先被添加到类的方法列表的最前面,B的drink方法会被添加到A的前面,所以后添加的B的drink方法被先执行了,故拦截了A的drink和原来类的drink,消息传递到B就执行了。

    二、extension:
    1、拓展 只生成一个.h文件,文件名形如Person+C, 相当于私有属性和方法(即类似于.m里 @interface里的属性和方法的声明)
    2、不能添加已有的属性 (相当于一个文件有两个同名属性,当然不行), 添加已有的属性会在编译期间报错 ,可以添加新属性
    3、可以添加同名方法(没有意义,因为extension没有自己的.m文件,方法实现还是依靠原类)、新方法。

    相关文章

      网友评论

          本文标题:iOS category和extension

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