2009-11-13 111 views
0

我打算用一個例子來正確說明我的困惑。我無法把頭繞在這裏。ObjectiveC中的循環#import/@類問題

在Cocoa touch中,我們有UIViewController及其子類UINavigationController。現在,UIVC有一個類型爲UINav的伊娃,並解決他們使用@class UINavigationController的循環導入問題。我假設他們然後在UIViewController.m#import "UINavigationController(或某些)。

我的困惑是:UIViewController的子類如何知道在UINavigationController中聲明的方法?在UIViewController子類中,可能會調用[self.navigationController popViewController],但該方法是如何知道的?

我唯一的想法是UINavigationController必須分別導入到每個子類中(也許在前綴?)

任何想法?

回答

1

如果此項目是使用其中一個Xcode模板創建的,那麼UIKit中所有類的標題可能都包含在該項目的預編譯標題中。

+0

想過更多之後,我意識到這是真的。編譯器並沒有做任何事情,事情正在被導入,它只是隱藏在其他頭文件和前綴中。謝謝! – jbrennan 2009-11-13 19:26:27

+0

沒有大量導入預編譯頭文件。 @class指令使編譯器向前搜索以查找實現文件中定義的頭。你可以通過創建具有循環引用的類來看到這一點。在我的答案中看到我的例子。 – TechZen 2009-11-14 17:15:07

+0

「沒有大量導入預編譯頭文件。」 在Xcode文檔中查找「項目頭文件」。問題是關於UIKit類;你的例子不適用。 – NSResponder 2009-11-15 19:49:43

0

它沒有導入標題隱藏。子類「知道」超類「知道」的一切。這是單一繼承設計的優勢之一。考慮3個班級;

ClassA.h

#import <Foundation/Foundation.h> 

@class ClassB; 
@interface ClassA : NSObject { 
    ClassB *bClass; 
} 
@property(nonatomic, retain) ClassB *bClass; 

@end 

ClassA.m

#import "ClassA.h" 
#import "ClassB.h" 

@implementation ClassA 
@synthesize bClass; 

-(ClassB *) bClass{ 
    return [[ClassB alloc] init]; 
} 
@end 

ClassB的:

#import <Foundation/Foundation.h> 

@class ClassA; 
@interface ClassB : NSObject { 
    ClassA *aClass; 
    NSString *name; 
} 
@property(nonatomic, retain) ClassA *aClass; 
@property(nonatomic, retain) NSString *name; 

@end 

ClassB.m

#import "ClassB.h" 
#import "ClassA.h" 

@implementation ClassB 
@synthesize aClass; 
@synthesize name; 

-(NSString *) name { return @"steve";} 
@end 

現在創建ClassA的子類: ClassC.h

#import <Foundation/Foundation.h> 
#import "ClassA.h" 

@interface ClassC : ClassA { 

} 

@end 

ClassC.m

#import "ClassC.h" 
@implementation ClassC 

@end 

當你調用ClassC的bclass的名稱方法:

#import "ClassC.h" 
... 
ClassC *c=[[ClassC alloc] init]; 
NSLog(@"c %@",[[c bClass] name]); //prints "c steve" 

子類固有進口頭他們的超類實現文件。

Edit01:

從評論:

試試這個:在ClassA.h定義一個宏, 然後嘗試使用ClassC.m (宏觀不導入ClassA.h有)。它 將不會編譯

在所有應有的尊重,我認爲這是不正確的。以下是編譯實際代碼並運行:

ClassA.h

#import <Foundation/Foundation.h> 

#define aMacro 5 

@class ClassB; 
@interface ClassA : NSObject { 
    ClassB *bClass; 
} 
@property(nonatomic, retain) ClassB *bClass; 
@end 

ClassC.h

#import <Foundation/Foundation.h> 
#import "ClassA.h" 

@interface ClassC : ClassA { 
} 
-(void) logMacro; 
@end 

ClassC.m

#import "ClassC.h" 

@implementation ClassC 
-(void) logMacro{ 
    NSLog(@"aMacro=%d",aMacro); 
}//-------------------------------------(void) logMacro------------------------------------ 
@end 

運行時間:

#import "ClassC.h" //the only header imported of the three classes .///////// 
... 
ClassC *c=[[ClassC alloc] init]; 
NSLog(@"c %@",[[c bClass] name]); 
[c logMacro]; //prints 5 

顯然,ClassC.m僅僅基於在ClassC.h中導入ClassA.h(它必須做的子類)來了解ClassA.h中定義的宏。

ClassC將不知道在ClassA.m中定義的宏,但這是因爲在實現中定義的宏實際上並不是該類的邏輯部分。 ClassA並不知道這個宏。這樣的宏不在類的名稱空間中,它只是由編譯器執行的簡單文本替換。 ClassC不知道這樣的替換,它知道ClassA在其方法的某個地方使用了實際的'5'。 ClassC不能固有這樣一個宏,因爲沒有什麼是固有的。

ClassC知道ClassA中定義的宏,因爲編譯器生成的ClassC的真正邏輯頭是由導入創建的鏈中所有頭的並集。 ClassC 知道所有ClassA都知道它知道Foundation框架知道的所有內容。

ClassC以類ClassA的方式瞭解ClassB。 @class指令使編譯器期待ClassB的定義,並在ClassA.m中找到它。幕後沒有大量頭文件的祕密輸入。這是父母面臨的問題。

+1

「在其超類實現文件中導入的頭文件的固有子類[sic]」不,它們不是。子類繼承超類的ivars,並且子類中的方法實現可以在其直接超類中調用方法實現。這就是所有的繼承。試試這個:在ClassA.h中定義一個宏,然後嘗試在ClassC.m中使用該宏(不需要在那裏導入ClassA.h)。它不會編譯。 – 2009-11-13 23:04:32