原文地址:http://blog.csdn.net/zeng_zhiming/article/details/70225456
加载及初始化类
运行时加载类或分类调用该方法,每个类只会调用一次
+(void)load;
类实例化使用前需要先初始化,一个类调用一次,如果子类没有实现该方法则会调用父类方法
+(void)initialize;
load
和initialize
区别在于:load
是只要类所在文件被引用就会被调用,而initialize
是在类或者其子类的第一个方法被调用前调用。所以如果类没有被引用进项目,就不会有load
调用;但即使类文件被引用进来,但是没有使用,那么initialize
也不会被调用;load
每个类只会调用一次,initialize
也只调用一次,但是如果子类没有实现initialize
方法则会调用父类的方法,因此作为父类的initialize
方法可能会调用多次。
2、分配内存空间及初始化对象
ZMStudent *student = [ZMStudent new];
ZMStudent *student2 = [[ZMStudent alloc] init];
ZMStudent *student3 = [[ZMStudent allocWithZone:nil] init];
创建新对象时,首先调用alloc
为对象分配内存空间,再调用init
初始化对象,如[[NSObject alloc] init]
;而new
方法先给新对象分配空间然后初始化对象,因此[NSObject new]
等同于[[NSObject alloc] init]
;关于allocWithZone
方法,官方文档解释该方法的参数是被忽略的,正确的做法是传nil或者NULL参数给它。
3、给对象发送消息(执行方法)
(1)直接调用
// 调用无参无返回值方法
[student running];
// 调用有参无返回值方法
[student readingWithText:@"Hello World!"];
// 调用有参有返回值方法
NSNumber *sum = [student sumWithNum:@(2) num2:@(3)];
我们通常都采用这种直接调用的方式,给对象发消息执行方法。这种方式调用编译时会自动校验方法、参数、返回值是否正确。因此我们必须在头文件中声明方法的使用。
(2)使用performSelector
执行
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
// 先判断对象是否能调用方法,再执行调用方法
if ([student respondsToSelector:@selector(running)]) {
// 调用无参无返回值方法
[student performSelector:@selector(running)];
}
if ([student respondsToSelector:@selector(readingWithText:)]) {
// 调用有参无返回值方法
[student performSelector:@selector(readingWithText:) withObject:@"Hello World"];
}
if ([student respondsToSelector:@selector(sumWithNum:num2:)]) {
// 调用有参有返回值方法
NSNumber *sum = [student performSelector:@selector(sumWithNum:num2:) withObject:@(2) withObject:@(8)];
}
使用performSelector:
是运行时系统负责去找方法,在编译时候不做任何校验;因此在使用时必须先使用respondsToSelector:
检查对象是否能调用方法,否则可能出现运行崩溃。performSelector:
常用于调用运行时添加的方法,即编译时不存在,但是运行时候存在的方法。另外需要注意的是performSelector:
系统提供最多接受两个参数的方法,而且参数和返回都是id
类型,并不支持基础数据类型(如:int, float等)。
(3)使用IMP指针调用
// 创建SEL
SEL runSel = @selector(running);
SEL readSel = NSSelectorFromString(@"readingWithText:");
SEL sumSel = NSSelectorFromString(@"sumWithNum:num2:");
// 调用无参无返回值方法
IMP rumImp = [student methodForSelector:runSel];
void (*runFunc)(id, SEL) = (voidvoid *)rumImp;
runFunc(student, runSel);
// 调用有参无返回值方法
IMP readImp = [[student class] instanceMethodForSelector:readSel];
void (*speakFunc)(id, SEL, NSString *) = (voidvoid *)readImp;
speakFunc(student, readSel, @"Hello World");
// 调用有参有返回值方法
IMP sumImp = [student methodForSelector:sumSel];
NSNumber *(*sumFunc)(id, SEL, NSNumber *, NSNumber *) = (voidvoid *)sumImp;
NSNumber *sum3 = sumFunc(student, sumSel, @(6), @(6));
SEL
是方法的索引。IMP是函数指针,指向方法的地址。SEL
与IMP
是一一对应的关系,因此我们可以通过修改对应关系达到运行时方法交换的目的。
创建SEL
对象两种方法:
1、使用@selector()
创建
2、使用NSSelectorFromString()
创建
获取方法IMP
指针两种方法:
1、- (IMP)methodForSelector:(SEL)aSelector;
实例方法
2、+ (IMP)instanceMethodForSelector:(SEL)aSelector;
类方法
4、复制对象
// 两个源数组
NSArray *sourceArrayI = [NSArray arrayWithObjects:@"I", @"I", nil nil];
NSMutableArray *sourceArrayM = [NSMutableArray arrayWithObjects:@"M", @"M", nil nil];
// 两个copy
NSArray *copyArrayI = [sourceArrayI copy];
NSArray *copyArrayM = [sourceArrayM copy];
// 两个mutableCopy
NSMutableArray *mutableArrayI = [sourceArrayI mutableCopy];
NSMutableArray *mutableArrayM = [sourceArrayM mutableCopy];
copy
拷贝为不可变对象,mutableCopy
拷贝为可变变量,copy
和mutableCopy
都可理解为复制了一个新对象。虽然copy
对静态对象只是引用计数加1,但是并不影响我们对复制前后的对象进行使用。需要注意的是对于容器对象而言,这两个方法只是复制了容器本身,对容器中包含的对象只是简单的指针引用,并没有深层复制。
5、获取Class
// 获取类
Class curClass1 = [student class];
Class curClass2 = [ZMStudent class];
// 获取父类
Class supClass1 = [student superclass];
Class supClass2 = [ZMStudent superclass];
6、判断方法
// 初始化对象
ZMPerson *person = [ZMPerson new];
ZMStudent *student = [ZMStudent new];
ZMStudent *student2 = student;
// 判断对象是否继承NSObject
if ([student isProxy]) {
NSLog(@"student对象是继承NSObject类");
}
// 判断两个对象是否相等
if ([student isEqual:student2]) {
NSLog(@"student对象与student2对象相等");
}
// 判断对象是否是指定类
if ([person isKindOfClass:[ZMPerson class]]) {
NSLog(@"person对象是ZMPerson类");
}
// 判断对象是否是指定类或子类
if ([student isKindOfClass:[ZMPerson class]]) {
NSLog(@"student对象是ZMPerson类的子类");
}
// 判断是否是另一个类的子类
if ([ZMStudent isSubclassOfClass:[ZMPerson class]]) {
NSLog(@"ZMStudent类是ZMPerson类的子类");
}
// 判判断对象是否遵从协议
if ([student conformsToProtocol:@protocol(NSObject)]) {
NSLog(@"student对象遵循NSObject协议");
}
// 判断类是否遵从给定的协议
if ([ZMStudent conformsToProtocol:@protocol(NSObject)]) {
NSLog(@"ZMStudent类遵循NSObject协议");
}
// 判断对象是否能够调用给定的方法
if ([student respondsToSelector:@selector(running)]) {
NSLog(@"student对象可以调用‘running’方法");
}
// 判断实例是否能够调用给定的方法
if ([ZMStudent instancesRespondToSelector:@selector(running)]) {
NSLog(@"ZMStudent类可以调用‘running’方法");
}