OC-分类(Category)

2,511 阅读3分钟

分类(Category)是OC中的特有语法,它是表示一个指向分类的结构体的指针。原则上它只能增加方法,不能增加成员(实例)变量。

Category的作用

为已经存在的类添加方法。可以在不修改原来类的基础上,为一个类 扩展方法。最主要的应用:给系统自带的类 扩展方法。

  • 注意

1.分类中只能添加“方法”,不能增加成员变量。分类中的可以写@property, 但不会生成setter/getter方法, 也不会生成实现以及私有的成员变量,会编译通过,但是引用变量会报错。

2.分类中可以/只能访问原有类中.h中的属性。如果想要访问本类中的私有变量,分类和子类一样,只能通过方法来访问。

3.在本类和分类有同名方法时,优先调用分类的方法。同名方法调用的优先级为分类 > 本类 > 父类

4.如果多个分类中都有和原有类中同名的方法,那么调用该方法的时候执行谁由编译器决定;编译器会执行最后一个参与编译的分类中的方法。

分类方法不会覆盖掉原来类中的方法,而是共存的。但是分类中的方法在前面,原来的类中的方法在后面,调用的时候,就会调用分类中的方法,如果多个分类有同样的方法,后编译的分类会调用。

创建分类

例如,创建一个UIView的分类:

- -

在新建的文件的.h中声明新方法,在.m中具体实现方法 格式:

@interface 待扩展类的类名(分类名字)
/*方法声明*/
@end
@implementation 待扩展类的类名(分类名字)
/*方法实现*/
@end

底层原理

编译完之后每一个分类都会生成一个结构体category_t ,里面存储着分类的对象方法、类方法、属性、协议信息。在程序运行的时候,runtime会将Category的数据,合并到类信息中(类对象、元类对象中)

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);
};

案例

UIImage的分类,添加扩展方法更改图片大小。

.h中

#import <UIKit/UIKit.h>

@interface UIImage (Size)

- (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize ;


@end

.m中



#import "UIImage+Size.h"

@implementation UIImage (Size)


- (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
    
    UIGraphicsBeginImageContext(newSize);
    [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return newImage;
}

@end

分类(Category)和类扩展(extension)的关系

1.类扩展(extension)是Category的一个特例,有时候也被称为匿名分类。他的作用是为一个类添加一些私有的成员变量和方法。 2.和分类不同,类扩展即可以声明成员变量又可以声明方法。 3.分类的小括号中必须有名字

Class Extension在编译的时候,它的数据就已经包含在类信息中。 Category是在运行时,才会将数据合并到类信息中。

其他

  • Category中有load方法吗? 有load方法,load方法在runtime加载类、分类的时候调用。load方法可以继承,但是一般情况下不会主动去调用load方法,都是让系统自动调用。