美文网首页
Category(分类)

Category(分类)

作者: 冰棍儿好烫嘴 | 来源:发表于2023-03-26 22:02 被阅读0次

基本用法:

Person文件:
#import <Foundation/Foundation.h>
@interface Person : NSObject
- (void)run;
+ (void)run2;
@end

#import "Person.h"
@implementation Person
- (void)run{
    NSLog(@"run");
}
+ (void)run2{
    NSLog(@"run2");
}
@end
Person+Test文件(Test分类)
#import "Person.h"
@interface Person (Test)
- (void)test;
+ (void)test2;
- (void)run;
@end

#import "Person+Test.h"
@implementation Person (Test)
- (void)test{
    NSLog(@"test");
}
+ (void)test2{
    NSLog(@"test2");
}
- (void)run{
    NSLog(@"test - run");
}
@end
Person+Eat文件(Eat分类)
#import "Person.h"
@interface Person (Eat)
- (void)eat;
+ (void)eat2;
- (void)run;
@end

#import "Person+Eat.h"
@implementation Person (Eat)
- (void)eat{
    NSLog(@"eat");
}
+ (void)eat2{
    NSLog(@"eat2");
}
- (void)run{
    NSLog(@"eat - run");
}
@end
Person *person = [[Person alloc] init];
[person run];

[person test];
[person eat];

[Person run2];
[Person test2];
[Person eat2];

通过runtime动态将分类的方法合并到类对象、元类对象中(程序运行过程中合并,而不是编译时)
程序编译时,所有的分类都变成了结构体,方法数据结构都存在结构体中

调用的run方法是Eat分类还是Test分类中的run方法,取决于最后编译的文件是哪个,最后编译的文件的方法列表会最先调用,如何判断先编译哪个文件,查看如下顺序。


Category的加载处理过程
1、通过Runtime加载某个类的所有Category数据
2、把所有Category的方法、属性、协议数据,合并到一个大数据中,后面参与编译的Category数据,会在数组的前面
3、将合并后的分类数据(方法、属性、协议),插入到类原来数据的前面

类扩展:
相当于.h文件里的属性或者方法,挪到.m文件中。公有化变私有化,编译时就在类对象里边了。和分类是不一样的。

#import "Person.h"
//class extension (匿名分类)也可以叫类扩展
@interface Person ()
{
    int _abc;
}
@property (nonatomic,assign) int age;
- (void)abc;
@end
@implementation Person
- (void)abc{
    NSLog(@"类扩展 - abc");
}
- (void)run{
    NSLog(@"run");
}
@end

探究Category中的load、initialize方法

+load方法
  • +load方法会在runtime加载类、分类时调用
  • 每个类、分类的+load,在程序运行过程中只调用一次
  • 调用顺序:
    1.先调用类的+load:按照编译先后顺序调用(先编译,先调用);调用子类的+load之前会先调用父类的+load
    2.再调用分类的+load:按照编译先后顺序调用(先编译,先调用)

新建继承自NSObject的Person类、Person的分类Test1、和Person的分类Test2、继承自Person类的Student类、Student类的分类Test1、Student的分类Test2.

Person文件
#import <Foundation/Foundation.h>
@interface Person : NSObject

@end

#import "Person.h"
@implementation Person
+ (void)load{
    NSLog(@"Person + load");
}

+ (void)test{
    NSLog(@"Person + test");
}
@end
Person+Test1文件
#import "Person.h"
@interface Person (Test1)

@end

#import "Person+Test1.h"
@implementation Person (Test1)
+ (void)load{
    NSLog(@"Person(Test1) + load");
}

+ (void)test{
    NSLog(@"Person(Test1) + test");
}
@end
Person+Test2文件
#import "Person.h"
@interface Person (Test2)

@end

#import "Person+Test2.h"
@implementation Person (Test2)
+ (void)load{
    NSLog(@"Person(Test2) + load");
}

+ (void)test{
    NSLog(@"Person(Test2) + test");
}
@end
Student文件
#import "Person.h"
@interface Student : Person

@end

#import "Student.h"
@implementation Student
+ (void)load{
    NSLog(@"Student + load");
}
@end
Student+Test1文件
#import "Student.h"
@interface Student (Test1)

@end

#import "Student+Test1.h"
@implementation Student (Test1)
+ (void)load{
    NSLog(@"Student (Test1) + load");
}
@end
Student+Test2文件
#import "Student.h"
@interface Student (Test2)

@end

#import "Student+Test2.h"
@implementation Student (Test2)
+ (void)load{
    NSLog(@"Student (Test2) + load");
}
@end
运行之后lldb打印结果
2023-03-23 15:56:32.764696+0800 interview[45205:125689529] Person + load
2023-03-23 15:56:32.765497+0800 interview[45205:125689529] Student + load
2023-03-23 15:56:32.765526+0800 interview[45205:125689529] Person(Test1) + load
2023-03-23 15:56:32.765547+0800 interview[45205:125689529] Person(Test2) + load
2023-03-23 15:56:32.765565+0800 interview[45205:125689529] Student (Test1) + load
2023-03-23 15:56:32.765584+0800 interview[45205:125689529] Student (Test2) + load
+ initialize方法
Person文件
#import <Foundation/Foundation.h>
@interface Person : NSObject

@end

#import "Person.h"
@implementation Person
+ (void)initialize{
    NSLog(@"Person + initialize");
}

+ (void)test{
    NSLog(@"Person + test");
}
@end
Person+Test1文件
#import "Person.h"
@interface Person (Test1)

@end

#import "Person+Test1.h"
@implementation Person (Test1)
+ (void)initialize{
    NSLog(@"Person(Test1) + initialize");
}

+ (void)test{
    NSLog(@"Person(Test1) + test");
}
@end
Person+Test2文件
#import "Person.h"
@interface Person (Test2)

@end

#import "Person+Test2.h"
@implementation Person (Test2)
+ (void)initialize{
    NSLog(@"Person(Test2) + initialize");
}

+ (void)test{
    NSLog(@"Person(Test2) + test");
}
@end
Student文件
#import "Person.h"
@interface Student : Person

@end

#import "Student.h"
@implementation Student
+ (void)initialize{
    NSLog(@"Student + initialize");
}
@end
Student+Test1文件
#import "Student.h"
@interface Student (Test1)

@end

#import "Student+Test1.h"
@implementation Student (Test1)
+ (void)initialize{
    NSLog(@"Student (Test1) + initialize");
}
@end
Student+Test2文件
#import "Student.h"
@interface Student (Test2)

@end

#import "Student+Test2.h"
@implementation Student (Test2)
+ (void)initialize{
    NSLog(@"Student (Test2) + initialize");
}
@end
Dog文件
#import <Foundation/Foundation.h>
@interface Dog : NSObject

@end

#import "Dog.h"
@implementation Dog
+ (void)initialize{
    NSLog(@"Dog + initialize");
}
@end
Cat文件
#import <Foundation/Foundation.h>
@interface Cat : NSObject

@end

#import "Cat.h"
@implementation Cat
+ (void)initialize{
    NSLog(@"Cat + initialize");
}
@end
Teacher文件,(继承自Person,但是.m文件中没有实现initialize方法)
#import "Person.h"
@interface Teacher : Person

@end

#import "Teacher.h"

@implementation Teacher

@end
main.m文件
[Person alloc];
lldb打印结果:
2023-03-23 17:00:02.419047+0800 interview[46841:125744184] Person(Test2) + initialize
[Student alloc];
lldb打印结果:
2023-03-23 18:54:33.026981+0800 interview[47435:125764517] Person(Test2) + initialize
2023-03-23 18:54:33.027458+0800 interview[47435:125764517] Student (Test2) + initialize

[Person alloc];
[Student alloc];
lldb打印结果:
2023-03-23 18:56:17.971696+0800 interview[47484:125766784] Person(Test2) + initialize
2023-03-23 18:56:17.972027+0800 interview[47484:125766784] Student (Test2) + initialize

[Teacher alloc];
lldb打印结果:
2023-03-23 19:30:35.313728+0800 interview[48235:125793488] Person(Test2) + initialize
2023-03-23 19:30:35.314508+0800 interview[48235:125793488] Person(Test2) + initialize
  • initialize方法会在类第一次接收到消息时调用
  • 调用顺序:
    1.先调用父类的+initialize,再调用子类的+initialize
    用Person和Student类举例:(伪代码)
if(Student 没有初始化){
    if(Person没有初始化){
          objc_msgSend([Person class],@selector(initialize));
     }
    objc_msgSend([Student class],@selector(initialize));
}

2.先初始化父类,再初始化子类,每个类只会初始化一次

  • +initialize和+load的很大区别是,+ initialize是通过objc_msgSend进行调用的,所以有以下特点
    1.如果子类没有实现+ initialize,会调用父类的+ initialize(所以父类的 + initialize可能会被调用多次)
    2.如果分类实现了+ initialize,就覆盖类本身的+ initialize调用

相关文章

网友评论

      本文标题:Category(分类)

      本文链接:https://www.haomeiwen.com/subject/ljymrdtx.html