原文地址:http://blog.csdn.net/zeng_zhiming/article/details/70225456
加載及初始化類
運(yùn)行時加載類或分類調(diào)用該方法,每個類只會調(diào)用一次
+(void)load;
類實例化使用前需要先初始化,一個類調(diào)用一次,如果子類沒有實現(xiàn)該方法則會調(diào)用父類方法
+(void)initialize;
load
和initialize
區(qū)別在于:load
是只要類所在文件被引用就會被調(diào)用,而initialize
是在類或者其子類的第一個方法被調(diào)用前調(diào)用。所以如果類沒有被引用進(jìn)項目,就不會有load
調(diào)用立砸;但即使類文件被引用進(jìn)來,但是沒有使用初茶,那么initialize
也不會被調(diào)用颗祝;load
每個類只會調(diào)用一次,initialize
也只調(diào)用一次恼布,但是如果子類沒有實現(xiàn)initialize
方法則會調(diào)用父類的方法螺戳,因此作為父類的initialize
方法可能會調(diào)用多次。
2折汞、分配內(nèi)存空間及初始化對象
ZMStudent *student = [ZMStudent new];
ZMStudent *student2 = [[ZMStudent alloc] init];
ZMStudent *student3 = [[ZMStudent allocWithZone:nil] init];
創(chuàng)建新對象時倔幼,首先調(diào)用alloc
為對象分配內(nèi)存空間,再調(diào)用init
初始化對象字支,如[[NSObject alloc] init]
凤藏;而new
方法先給新對象分配空間然后初始化對象,因此[NSObject new]
等同于[[NSObject alloc] init]
堕伪;關(guān)于allocWithZone
方法,官方文檔解釋該方法的參數(shù)是被忽略的栗菜,正確的做法是傳nil或者NULL參數(shù)給它欠雌。
3、給對象發(fā)送消息(執(zhí)行方法)
(1)直接調(diào)用
// 調(diào)用無參無返回值方法
[student running];
// 調(diào)用有參無返回值方法
[student readingWithText:@"Hello World!"];
// 調(diào)用有參有返回值方法
NSNumber *sum = [student sumWithNum:@(2) num2:@(3)];
我們通常都采用這種直接調(diào)用的方式疙筹,給對象發(fā)消息執(zhí)行方法富俄。這種方式調(diào)用編譯時會自動校驗方法、參數(shù)而咆、返回值是否正確霍比。因此我們必須在頭文件中聲明方法的使用。
(2)使用performSelector
執(zhí)行
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
// 先判斷對象是否能調(diào)用方法暴备,再執(zhí)行調(diào)用方法
if ([student respondsToSelector:@selector(running)]) {
// 調(diào)用無參無返回值方法
[student performSelector:@selector(running)];
}
if ([student respondsToSelector:@selector(readingWithText:)]) {
// 調(diào)用有參無返回值方法
[student performSelector:@selector(readingWithText:) withObject:@"Hello World"];
}
if ([student respondsToSelector:@selector(sumWithNum:num2:)]) {
// 調(diào)用有參有返回值方法
NSNumber *sum = [student performSelector:@selector(sumWithNum:num2:) withObject:@(2) withObject:@(8)];
}
使用performSelector:
是運(yùn)行時系統(tǒng)負(fù)責(zé)去找方法悠瞬,在編譯時候不做任何校驗;因此在使用時必須先使用respondsToSelector:
檢查對象是否能調(diào)用方法涯捻,否則可能出現(xiàn)運(yùn)行崩潰浅妆。performSelector:
常用于調(diào)用運(yùn)行時添加的方法,即編譯時不存在障癌,但是運(yùn)行時候存在的方法凌外。另外需要注意的是performSelector:
系統(tǒng)提供最多接受兩個參數(shù)的方法,而且參數(shù)和返回都是id
類型涛浙,并不支持基礎(chǔ)數(shù)據(jù)類型(如:int, float等)康辑。
(3)使用IMP指針調(diào)用
// 創(chuàng)建SEL
SEL runSel = @selector(running);
SEL readSel = NSSelectorFromString(@"readingWithText:");
SEL sumSel = NSSelectorFromString(@"sumWithNum:num2:");
// 調(diào)用無參無返回值方法
IMP rumImp = [student methodForSelector:runSel];
void (*runFunc)(id, SEL) = (voidvoid *)rumImp;
runFunc(student, runSel);
// 調(diào)用有參無返回值方法
IMP readImp = [[student class] instanceMethodForSelector:readSel];
void (*speakFunc)(id, SEL, NSString *) = (voidvoid *)readImp;
speakFunc(student, readSel, @"Hello World");
// 調(diào)用有參有返回值方法
IMP sumImp = [student methodForSelector:sumSel];
NSNumber *(*sumFunc)(id, SEL, NSNumber *, NSNumber *) = (voidvoid *)sumImp;
NSNumber *sum3 = sumFunc(student, sumSel, @(6), @(6));
SEL
是方法的索引摄欲。IMP是函數(shù)指針,指向方法的地址疮薇。SEL
與IMP
是一一對應(yīng)的關(guān)系胸墙,因此我們可以通過修改對應(yīng)關(guān)系達(dá)到運(yùn)行時方法交換的目的。
創(chuàng)建SEL
對象兩種方法:
1惦辛、使用@selector()
創(chuàng)建
2劳秋、使用NSSelectorFromString()
創(chuàng)建
獲取方法IMP
指針兩種方法:
1、- (IMP)methodForSelector:(SEL)aSelector;
實例方法
2胖齐、+ (IMP)instanceMethodForSelector:(SEL)aSelector;
類方法
4玻淑、復(fù)制對象
// 兩個源數(shù)組
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
都可理解為復(fù)制了一個新對象补履。雖然copy
對靜態(tài)對象只是引用計數(shù)加1,但是并不影響我們對復(fù)制前后的對象進(jìn)行使用剿另。需要注意的是對于容器對象而言箫锤,這兩個方法只是復(fù)制了容器本身,對容器中包含的對象只是簡單的指針引用雨女,并沒有深層復(fù)制谚攒。
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é)議");
}
// 判斷對象是否能夠調(diào)用給定的方法
if ([student respondsToSelector:@selector(running)]) {
NSLog(@"student對象可以調(diào)用‘running’方法");
}
// 判斷實例是否能夠調(diào)用給定的方法
if ([ZMStudent instancesRespondToSelector:@selector(running)]) {
NSLog(@"ZMStudent類可以調(diào)用‘running’方法");
}