Extension与Category
目录
一,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,单独文件:很少使用

// .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

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


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

-
如何使用
1,在原类中:很少使用
// .h文件
@interface ViewController : UIViewController
@end
@interface ViewController (Category)
//声明方法
@end
// .m文件
@implementation ViewController
@end
@implementation ViewController (Category)
//实现方法
@end
2,单独文件:经常使用

// .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,编译期加载;运行期加载