2013年8月14日 星期三

Objective-C Inheritance

繼承總要有個來源,在Objective-C 中, NSObject 是所有的類別的源頭,所以時常可以看到
@interface ClassA : NSObject
    ................
@end

self, super
-(id)init
{
    self = [super init];
    if(self) {
        // Initialize code here
    }
    return self;
}

在建構子中,我們常常這樣寫,self 表示自己,super則是父類別,而這段程式是先使用父類別的建構子,如果生成成功,進行子類別的初始化工作,最後回傳。

@class

在類別中要使用別的類別,通常我們都在.h檔中去import另一個類別的標頭檔,
#import "ClassB.h"  // ClassA.h
也可以使用@class這個關鍵字去告訴complier,會更有效率的多
@class ClassB     // ClassA.h
這裡會用到ClassB這個類別,你不用知道它的內容是什麼,儘管編譯過就是了。但事情沒這麼簡單,如果在ClassA.m檔中,有用到ClassB的方法,這時候編譯器怎麼會知道ClassB中的方法內容,就會出現錯誤。



把ClassA.m 檔中匯入ClassB.h檔就可以解決這個問題

#import "ClassB.h"   // ClassA.m

那為何不一開始就在ClassA.h中,直接import ClassB.h檔就好了呢,是啊!!這樣不是多此一舉嗎~~所以使用時機是當你不會用到另一個類別的方法時,用 @class節省編譯很多時間。

另外,有一種情況是非用不可,那就是 circular inclusions,
#import "ClassB.h"  // ClassA.h
#import "ClassA.h" //  ClassB.h

這裡就需要用到@class,就不會再編譯的階段一直無窮的交互import。下面的例子,因為都有用到對方的方法,所以在.m中都需要 import 對方的.h檔。

ClassA.h
#import <Foundation/Foundation.h>
@class  ClassB;
@interface ClassA : NSObject
{
    NSString *name;
    ClassB *b;
}

-(NSString *)name;
-(NSString *)theNameOfB;

@end
ClassA.m
#import "ClassA.h"
#import "ClassB.h"

@implementation ClassA
-(id)init
{
    self = [super init];
    if (self) {
        name = @"A";
    }
    return self;
}

-(NSString *)name
{
    return name;
}
-(NSString *)theNameOfB
{
    if (!b) {
        b = [[ClassB alloc]init];
    }
    return b.name;
}
@end

ClassB.h
#import <Foundation/Foundation.h>
@class ClassA;

@interface ClassB : NSObject
{
    ClassA *a;
    NSString *name;
}

-(NSString *)name;
-(NSString *)theNameOfA;

@end
ClassB.m
#import "ClassB.h"
#import "ClassA.h"

@implementation ClassB


-(id)init
{
    
    self = [super init];
    if (self) {
        name = @"B";
    }
    return self;
    
}

-(NSString *)name
{
    return name;
}

-(NSString *)theNameOfA
{
    if (!a) {
        a = [[ClassA alloc]init];
    }
    return a.name;
}

@end

main.m
#import <Foundation/Foundation.h>
#import "ClassA.h"
#import "ClassB.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        ClassA *a = [[ClassA alloc]init];
        NSLog(@"ClassA use classB method, the name of ClassB : %@",[a theNameOfB]);
        
        ClassB *b = [[ClassB alloc]init];
        NSLog(@"ClassB use classA method, the name of ClassA : %@",[b theNameOfA]);
    }
    return 0;
}


輸出結果

沒有留言: