Objective-C

Extension与Category

2019-04-11  本文已影响1人  码小菜

目录
一,Extension(扩展)
二,Category(分类)
 1,作用
 2,特点
 3,如何使用
 4,使用场景
 5,底层代码
 6,问题分析
三,Extension与Category的区别

一,Extension(扩展)

为原类添加方法,属性和成员变量

1,匿名的
2,只有声明,没有独立的实现部分,必须依靠原类来实现
3,在编译期加载

1,在原类.h中:很少使用

@interface ViewController : UIViewController
@end

@interface ViewController ()
//声明方法,属性和成员变量
@end

2,在原类.m中:经常使用

@interface ViewController ()
//声明方法,属性和成员变量,方法声明可以省略
@end

@implementation ViewController
// 都在此实现
@end

3,单独文件:很少使用

ViewController+Extension.png
// .h文件
@interface ViewController ()
//声明方法,属性和成员变量
@end

// 无.m文件

1,为自定义类声明私有属性
2,为自定义类声明外部不能修改但内部可以修改的属性

二,Category(分类)

1,为原类添加方法

2,可以添加属性,但不会生成get/set方法和带下划线的成员变量,若添加会报如下警告,意思是必须定义属性name的get/set方法,@dynamic是告诉系统会手动添加,这样系统就不报警告了,但想正常使用属性name还是要把get/set方法给添加上

@interface ViewController : UIViewController
@end

@interface ViewController (Category)
@property (nonatomic, copy) NSString *name;
@end
添加属性.png

3,不能添加成员变量,若添加会报如下错误,意思是成员变量不能放在分类中,另外也不能用@synthesize来添加

添加成员变量1.png 添加成员变量2.png

1,在运行期加载
2,与原类的同名方法,优先调用分类的,因为分类方法放在方法列表的前面,原类方法放在后面
3,多个分类的同名方法,优先调用后面编译的,编译顺序从上往下,所以下图中优先调用ViewController+Two中的方法

编译顺序.png

1,在原类中:很少使用

// .h文件
@interface ViewController : UIViewController
@end

@interface ViewController (Category)
//声明方法
@end

// .m文件
@implementation ViewController
@end

@implementation ViewController (Category)
//实现方法
@end

2,单独文件:经常使用

ViewController+Category.png
// .h文件
@interface ViewController (Category)
// 声明方法
@end

// .m文件
@implementation ViewController (Category)
// 实现方法
@end

1,给系统类添加方法

2,给系统类添加属性

// .h文件
@interface UIView (Category)
@property (nonatomic, copy) NSString *name;
@end

// .m文件
@implementation UIView (Category)
- (NSString *)name {
    return objc_getAssociatedObject(self, @selector(name));
}

- (void)setName:(NSString *)name {
    objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

3,拆分自定义类的代码
 >减小类的体积
 >便于多人共同维护一个类,每人维护各自的分类即可

1,Class:指向结构体objc_class的指针

typedef struct objc_class *Class;

2,objc_class:在运行期内存大小已经确定

struct objc_class {
    Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
    Class super_class                       OBJC2_UNAVAILABLE;
    const char *name                        OBJC2_UNAVAILABLE;
    long version                            OBJC2_UNAVAILABLE;
    long info                               OBJC2_UNAVAILABLE;
    long instance_size                      OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars            OBJC2_UNAVAILABLE; // 成员变量列表
    struct objc_method_list **methodLists   OBJC2_UNAVAILABLE; // 方法列表
    struct objc_cache *cache                OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;

3,category:本质是结构体

typedef 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; // 属性列表
} category_t;

1,为什么不能添加成员变量?

答:category是在运行期加载的,运行期objc_class的内存大小已经确定,所以ivars指针指向的内存空间是固定的,无法添加新的成员变量;另外category_t中也缺少成员变量列表指针

2,为什么能添加方法?

答:虽然methodLists指针指向的内存空间是固定的,但存放的是objc_method_list指针,而objc_method_list指针指向的内存空间是可以扩展的,所以我们可以通过修改objc_method_list指针来添加方法;另外category_t中也包含方法列表指针

3,为什么能添加属性?为什么不能生成get/set方法?

答:category_t中包含属性列表指针;成员变量是生成get/set方法的前提条件

三,Extension与Category的区别

1,匿名;必须命名
2,添加方法,属性和成员变量,没有独立的实现部分;添加方法和属性(需要手动添加set/get方法)
3,主要存在于原类.m文件中;主要存在于单独文件
4,用于自定义类;系统类和自定义类都会用到
5,编译期加载;运行期加载

上一篇 下一篇

猜你喜欢

热点阅读