原文地址:http://blog.csdn.net/zeng_zhiming/article/details/70225456
加載及初始化類
運行時加載類或分類調用該方法,每個類只會調用一次
+(void)load;
類實例化使用前需要先初始化,一個類調用一次,如果子類沒有實現該方法則會調用父類方法
+(void)initialize;
load和initialize區(qū)別在于:load是只要類所在文件被引用就會被調用,而initialize是在類或者其子類的第一個方法被調用前調用。所以如果類沒有被引用進項目,就不會有load調用;但即使類文件被引用進來,但是沒有使用,那么initialize也不會被調用;load每個類只會調用一次,initialize也只調用一次,但是如果子類沒有實現initialize方法則會調用父類的方法,因此作為父類的initialize方法可能會調用多次。
2、分配內存空間及初始化對象
ZMStudent *student = [ZMStudent new];
ZMStudent *student2 = [[ZMStudent alloc] init];
ZMStudent *student3 = [[ZMStudent allocWithZone:nil] init];
創(chuàng)建新對象時,首先調用alloc為對象分配內存空間,再調用init初始化對象,如[[NSObject alloc] init];而new方法先給新對象分配空間然后初始化對象,因此[NSObject new]等同于[[NSObject alloc] init];關于allocWithZone方法,官方文檔解釋該方法的參數是被忽略的,正確的做法是傳nil或者NULL參數給它。
3、給對象發(fā)送消息(執(zhí)行方法)
(1)直接調用
// 調用無參無返回值方法
[student running];
// 調用有參無返回值方法
[student readingWithText:@"Hello World!"];
// 調用有參有返回值方法
NSNumber *sum = [student sumWithNum:@(2) num2:@(3)];
我們通常都采用這種直接調用的方式,給對象發(fā)消息執(zhí)行方法。這種方式調用編譯時會自動校驗方法、參數、返回值是否正確。因此我們必須在頭文件中聲明方法的使用。
(2)使用performSelector執(zhí)行
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
// 先判斷對象是否能調用方法,再執(zhí)行調用方法
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:是運行時系統(tǒng)負責去找方法,在編譯時候不做任何校驗;因此在使用時必須先使用respondsToSelector:檢查對象是否能調用方法,否則可能出現運行崩潰。performSelector:常用于調用運行時添加的方法,即編譯時不存在,但是運行時候存在的方法。另外需要注意的是performSelector:系統(tǒng)提供最多接受兩個參數的方法,而且參數和返回都是id類型,并不支持基礎數據類型(如:int, float等)。
(3)使用IMP指針調用
// 創(chuàng)建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是一一對應的關系,因此我們可以通過修改對應關系達到運行時方法交換的目的。
創(chuàng)建SEL對象兩種方法:
1、使用@selector()創(chuàng)建
2、使用NSSelectorFromString()創(chuàng)建
獲取方法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對靜態(tài)對象只是引用計數加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類的子類");
}
// 判判斷對象是否遵從協(xié)議
if ([student conformsToProtocol:@protocol(NSObject)]) {
NSLog(@"student對象遵循NSObject協(xié)議");
}
// 判斷類是否遵從給定的協(xié)議
if ([ZMStudent conformsToProtocol:@protocol(NSObject)]) {
NSLog(@"ZMStudent類遵循NSObject協(xié)議");
}
// 判斷對象是否能夠調用給定的方法
if ([student respondsToSelector:@selector(running)]) {
NSLog(@"student對象可以調用‘running’方法");
}
// 判斷實例是否能夠調用給定的方法
if ([ZMStudent instancesRespondToSelector:@selector(running)]) {
NSLog(@"ZMStudent類可以調用‘running’方法");
}