load方法(原理+调用顺序)
面试题:
1.load它的调用顺序?
析:load方法会在runtime加载【类】、【分类】的时候调用
每个【类】、【分类】的+load,在程序运行过程中只调用一次
调用顺序:
a.先调用类的+load方法
(1)按照编译先后的顺序调用(先编译、先调用)
(2)调用子类的+load之前会先调用父类的+load方法
b.再调用分类的+load方法
(1).按照编译先后的顺序调用(先编译、先调用)
2.系统的load的原理?
析:见下详解
准备:首先搭建好可以跑runtime源码的过程,参考配置运行objc4-750和使用
下面我们来看看代码执行:
Animal.h
#import <Foundation/Foundation.h>
@interface Animal : NSObject
@end
Animal.m
#import "Animal.h"
@implementation Animal
+ (void)load{
NSLog(@"Animal");
}
@end
------------------------
Animal2.h
#import <Foundation/Foundation.h>
@interface Animal2 : NSObject
@end
Animal2.m
#import "Animal2.h"
@implementation Animal2
+ (void)load{
NSLog(@"Animal2");
}
@end
------------------------
Person.h
#import "Animal.h"
@interface Person : Animal
@end
Person.m
#import "Person.h"
@implementation Person
+ (void)load{
NSLog(@"Person");
}
@end
-----------------------
Student.h
#import "Person.h"
@interface Student : Person
@end
Student.m
#import "Student.h"
@implementation Student
+ (void)load{
NSLog(@"Student");
}
@end
------------------------
Animal+myAnimal.h
#import "Animal.h"
@interface Animal (myAnimal)
@end
Animal+myAnimal.m
#import "Animal+myAnimal.h"
@implementation Animal (myAnimal)
+ (void)load{
NSLog(@"分类--Animal");
}
@end
------------------------
Person+myPerson.h
#import "Person.h"
@interface Person (myPerson)
@end
Person+myPerson.m
#import "Person+myPerson.h"
@implementation Person (myPerson)
+ (void)load{
NSLog(@"分类--Person");
}
@end
------------------------
Student+myStudent.h
#import "Student.h"
@interface Student (myStudent)
@end
Student+myStudent.m
#import "Student+myStudent.h"
@implementation Student (myStudent)
+ (void)load{
NSLog(@"分类--Student");
}
@end
------------------------
运行结果 :
分析:
- 根据加载的类的顺序:
- 先执行了Animal2类
- 再执行了Animal类
- 再执行了Animal的子类Peson类
- 再执行了Person的子类Student类
- 等所有的类加载完了,就按照加载的顺序执行分类(先编译,先调用原则)
- 分类Peson+myPerson
- 分类Student+myStudent
- 分类Animal+myAnimal
OR:
在:Edit Scheme.. -> Run_debug. -> Arguments -> Environment variables 中添加 :OBJC_PRINT_LOAD_METHODS为YES (为什么这么设置?:我们通过下面分析源码,发现add_class_to_loadable_list方法里面有打印的设置【PrintLoading】)
见后台部分打印:
objc[91622]: LOAD: class 'Animal2' scheduled for +load
objc[91622]: LOAD: class 'Animal' scheduled for +load
objc[91622]: LOAD: class 'Person' scheduled for +load
objc[91622]: LOAD: class 'Student' scheduled for +load
objc[91622]: LOAD: category 'Person(myPerson)' scheduled for +load
objc[91622]: LOAD: category 'Student(myStudent)' scheduled for +load
objc[91622]: LOAD: category 'Animal(myAnimal)' scheduled for +load
objc[91622]: LOAD: +[Animal2 load]
原理:
1.首先 我们打个 断点—>如下
我们看左边:发现执行了load_images方法,点击进去
我们通过找到load_images,然后根据上下文打断点
补充:
1.分类的test方法(类方法和实例方法),是通过 objc_mesgSend的方法的(isa)来执行方法的
2.一般系统自动调用的load方法不一样哟,但是[Student load]; 手动调用的时候是通过消息发送机制的 先调用分类的(如果分类没写),再调用本类的(如果本类没写),会自动调用父类的load方法
分析
Student+myStudent.h
#import "Student.h"
@interface Student (myStudent)
+(void)play;
-(void)walk;
@end
Student+myStudent.m
#import "Student+myStudent.h"
@implementation Student (myStudent)
+ (void)load{
NSLog(@"分类--Student");
}
+(void)play{
NSLog(@"Student的分类的类方法play");
}
-(void)walk{
NSLog(@"Student的分类的实例方法walk");
}
@end
---------------
main.m
#import <Foundation/Foundation.h>
#import "Student+myStudent.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
[Student play]; //打个断点
NSLog(@"-------------");
Student *stu = [Student new];
[stu walk];
NSLog(@"-------------");
[Student load]; //打个断点
}
return 0;
}
友情链接: