ios NSObject.h 詳解

原文地址:http://blog.csdn.net/zeng_zhiming/article/details/70225456

加載及初始化類

運行時加載類或分類調用該方法,每個類只會調用一次

+(void)load;

類實例化使用前需要先初始化,一個類調用一次,如果子類沒有實現該方法則會調用父類方法

+(void)initialize;

loadinitialize區(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是函數指針,指向方法的地址。SELIMP是一一對應的關系,因此我們可以通過修改對應關系達到運行時方法交換的目的。
創(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拷貝為可變變量,copymutableCopy都可理解為復制了一個新對象。雖然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’方法");  
    }  
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容