开发中涉及到的方方面面

分类Category、扩展Extension 分析

2019-11-07  本文已影响0人  四月_Hsu

前言

引用 iOS分类(category),类扩展(extension)—史上最全攻略

分类 Category

概念

分类 CatgegoryOC 中特有的语法,他表示一个指向分类的结构体指针。原则上,分类只能增加方法,不能添加变量。但是可以通过 runtime 实现变量的添加。

源码

runtime.h 中实现:

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; // 分类所实现的协议列表
}

objc-runtime-new.h 中实现:

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 property_list_t *instanceProperties;
    // Fields below this point are not always present on disk.
    struct property_list_t *_classProperties;

    method_list_t *methodsForMeta(bool isMeta) {
        if (isMeta) return classMethods;
        else return instanceMethods;
    }

    property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
};

以上,可以看出,分类中既有实例方法、类方法的存储列表,也有实例属性、类属性的列表。但是变量列表仅仅定义了,并未做返回设置。个人猜测,这也是为啥么添加成员变量,访问会崩溃的原因

注意:

分类格式

@interface 待扩展的类(分类的名称)
@end

@implementation 待扩展的名称(分类的名称)
@end

举例:

//  Programmer+Category.h文件中
@interface Programmer (Category)

@property(nonatomic,copy) NSString *nameWithSetterGetter;           //设置setter/getter方法的属性

@property(nonatomic,copy) NSString *nameWithoutSetterGetter;        //不设置setter/getter方法的属性(注意是可以写在这,而且编译只会报警告,运行不报错)

- (void) programCategoryMethod;                                     //分类方法

@end

//  Programmer+Category.m文件中

下面通过 runtime 实现分类添加属性的功能:

#import <objc/runtime.h>

static NSString *nameWithSetterGetterKey = @"nameWithSetterGetterKey";   //定义一个key值
@implementation Programmer (Category)

//运行时实现setter方法
- (void)setNameWithSetterGetter:(NSString *)nameWithSetterGetter {
        objc_setAssociatedObject(self, &nameWithSetterGetterKey, nameWithSetterGetter, OBJC_ASSOCIATION_COPY);
}

//运行时实现getter方法
- (NSString *)nameWithSetterGetter {
    return objc_getAssociatedObject(self, &nameWithSetterGetterKey);
}

@end

类扩展 Class Extension

ExtensionCategory 的一个特例。类扩展因为不包含分类名称,又称 匿名分类

开发中,我们几乎天天在使用类扩展。

类扩展格式:

@interface XXX ()
//私有属性
//私有方法(如果不实现,编译时会报警,Method definition for 'XXX' not found)
@end

类扩展作用:

分类 VS 扩展

  1. 分类中原则上只能添加方法。可通过 runtime 添加属性不能添加成员变量。
  2. 类扩展可以添加属性、方法、成员变量。但默认是 private 类型的。
  3. 分类中,如果方法、属性没有实现,会有警告。扩展则不会有警告。因为。扩展是在编译阶段加到类中,而类别则是运行时加到类中
  4. 扩展没有单独实现的部分,即 @implementation。需要依赖主类 .m 文件实现定义的功能。
  5. .h 中类扩展方法、属性是对外共有的,.m 中类扩展中声明的,都是私有的。
上一篇 下一篇

猜你喜欢

热点阅读