iOS 中的Category 和 Extension

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/heipingguowenkong/article/details/88305557

iOS 中的Category 和 Extension 的特点及用法

Category(分类):

category即oc中通常称为分类/类别,主要作用有以下几点:

  • 为已有的类添加方法,扩展功能;
  • 可以实现多个开发者共同开发同一个类。
  • 为单一的类文件减小文件大小。
  • 可以将类的功能进行分类,不同的功能可以放在不同Category中。
  • 按功能需求选择性加载不同的Category;
  • 声明私有方法。
  • 模拟oc不支持的多继承,另外使用protocol也可以模拟多继承。

Category有以下一些特点:

  • 只可以给已有的类添加方法,但是无法添加成员变量;
  • 不能直接在分类中添加属性,虽然Category的.h文件中也可以使用@property来声明类的属性,但是不会生成带“_”的成员变量,也不会生成set 和 get方法,如果一定要在分类中为类添加属性,可以通过runtime中的动态绑定对象方法来实现,示例如下:
categor.h中如下:

@interface UIView (UIView_cate)
//添加的属性
@property(nonatomic,copy)NSString * lm_name;

-(void)addParametter:(NSString *) value;
@end

category.m中 实现如下:

#import "UIView+UIView_cate.h"
#import <objc/runtime.h>
//runtime 动态给分类添加属性
static const char * k_name = "lm_name";

@implementation UIView (UIView_cate)

-(NSString*)lm_name{
    
    return objc_getAssociatedObject(self, k_name);
}

-(void)setLm_name:(NSString*)name{
    
    objc_setAssociatedObject(self, k_name, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
  • 如果分类和原类中出现了同名方法时,运行时会优先调用分类中的方法,也就是说分类中的方法会覆盖原类中的同名方法。所以我们在分类中的方法命名不可与原类中重复,可以加自定义的前缀。方法调用优先级为:分类 --> 原类 --> 父类;
  • 如果同一个类的多个分类中有同名方法,则调用顺序由编译器决定,会优先调用最后一个编译的同名分类方法。编译顺序可在项目的Compile source中查看和修改;

关于分类中为何无法添加成员变量:

oc的类Class在运行时是一个指向结构体的指针(typedef struct objc_class *Class;);在该结构体中,ivars 就是一个objc_ivar_list的指针,由于它指向的地址是一个固定的存储区域,并且Class结构体指针指向的区域大小也是固定的,所以只能修改ivars地址中成员变量值,不能添加新的成员变量。而方法列表则不同,它是一个objc_method_list **methodLists(指向方法列表的指针的指针),我们虽无法扩展他的大小,但是可以改变它值(存的是指针),所以可以动态添加方法;

Extension(扩展):

oc中的的扩展,主要是为类声明私有的属性。与Category不同的是,Extension如果单独建立文件只有一个.h文件,没有实现的.m文件。所以一般我们会把Extension与自定义类的实现文件放在一起;示例如下:

@interface ViewController ()//扩展部分
@property(nonatomic,strong)dispatch_queue_t chekQ;
@property(nonatomic,assign)BOOL stop;
@property(nonatomic,copy)BreakCall breakCall;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.automaticallyAdjustsScrollViewInsets = YES;
    self.edgesForExtendedLayout = UIRectEdgeBottom;

如果为一个系统的类建立扩展,可以为系统的类添加属性和成员变量,在扩展中添加的属性会自动生成set 和 get 方法以及带“_”的成员变量;示例如下:

//UIView的扩展
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN

@interface UIView ()

@property(nonatomic, copy)NSString* name;
@end

NS_ASSUME_NONNULL_END
//控制器中使用
#import "ViewController.h"
#import "UIview+EXT.h"
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.name = @"人间四月芳菲尽,山寺桃花始盛开!";
    NSLog(@"view.name : %@", view.name);
}
//打印内容
2019-03-06 19:05:57.115318+0800 test[46589:1604581] view.name : 人间四月芳菲尽,山寺桃花始盛开!

猜你喜欢

转载自blog.csdn.net/heipingguowenkong/article/details/88305557