iOS 分类 category

2018-10-21  本文已影响0人  逐日追星看月亮

1. 分类是什么

分类是利用 OC 的动态运行时机制,实现对一个现有类的功能进行扩展而不必知道该类的源码。所以分类不仅可以扩展自定义类,也可以扩展系统类如 NSString 等;分类提供了一种比继承更简洁的方法对类进行功能扩展,无需创建子类就能为现有类添加新的方法。

底层结构
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);
};

从源码基本可以看出平时使用categroy的方式,对象方法,类方法,协议,和属性都可以找到对应的存储方式。并且发现分类结构体中是不存在成员变量的,因此分类中是不允许添加成员变量的。
由源码可知,分类的方法和属性列表是存储在分类结构体中的,在运行时,会检查现有类是否存在分类,存在的话会遍历分类列表,将各个分类下对应的方法及属性列表插入到现有类的方法和属性列表前面,这样做的目的是为了保证分类方法优先调用,我们知道当分类重写本类的方法时,会覆盖本类的方法。其实本质上并不是覆盖,而是优先调用。本类的方法依然在内存中的。

Person.h
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Person : NSObject
{
    NSString *_name;
    NSInteger _age;
}
- (void)speak;
@end

NS_ASSUME_NONNULL_END

Person.m
#import "Person.h"

@implementation Person

-(void)speak
{
    NSLog(@"Person---speak");
}

-(void)walk
{
    NSLog(@"Person---walk");
}
@end

2.category的作用

(1)将类的实现分散到多个不同的文件中,方便代码管理,也可以对框架提供的类进行扩展。(可以减少单个类的体积,把不同的功能组织到不同的 category 里,可以由多个开发者共同完成一个类,可以按需加载想要的 category);

Person + Test1.h
#import "Person.h"
NS_ASSUME_NONNULL_BEGIN

@interface Person (Test1)

- (void)eat;

@end

NS_ASSUME_NONNULL_END

Person+Test1.m
#import "Person+Test1.h"
@implementation Person (Test1)

- (void)eat{
    NSLog(@"Person+Test1---eat");
}
@end

(2)创建对私有方法的前向引用:如果原有类中有未在头文件中声明的私有方法,你在访问该私有方法的时候编译器就会报错,这时就可以使用分类,在分类中声明该私有方法将其公开(不必提供方法实现);

Person + Test2.h
#import "Person.h"
NS_ASSUME_NONNULL_BEGIN

@interface Person (Test2)
- (void)walk;
@end

NS_ASSUME_NONNULL_END

Person + Test2.h
#import "Person+Test2.h"
@implementation Person (Test2)

@end

在其他类中访问原有类的私有方法:

#import "ViewController.h"
#import "Person.h"
#import "Person+Test1.h"
#import "Person+Test2.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    Person *person = [[Person alloc]init];
    //原有类方法
    [person speak];
    //分类扩展方法
    [person eat];
    //利用方法创建对私有方法的前向引用
    [person walk];
    
}
@end

(3)向对象添加非正式协议:创建一个 NSObject 的分类称为“创建一个非正式协议”,因为可以作为任何类(NSObject 为任意类的父类)的委托对象使用(声明私有方法)。

NSObject+Test3.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSObject (Test3)
- (void)sleep;
@end
NS_ASSUME_NONNULL_END

NSObject+Test3.m
#import "NSObject+Test3.h"

@implementation NSObject (Test3)

-(void)sleep
{
    NSLog(@"NSObject + Test3 --- sleep");
}
@end
  Person *person = [[Person alloc]init];
    //原有类方法
    [person speak];
    //分类扩展方法
    [person eat];
    //利用方法创建对私有方法的前向引用
    [person walk];
    
    [person sleep];

3.category的局限性

4.常见问题总结

上一篇 下一篇

猜你喜欢

热点阅读