![](/img/trans.png)
[英]In Objective-C, what's difference between import in header file and implementation file?
[英]In Objective-C what is the difference between defining something (say a property) in the header file as opposed to the .m file?
在Objective-C中,在頭文件中定義某些內容(比如屬性或方法)與.m文件相比有什么區別? 我聽說它與公開或私人有關,但我不確定細節。 如果是這種情況,這與Java中的公共和私有方法相同嗎?
我精通Java,所以任何可以將Objective-C與它聯系起來的方式都會有所幫助。
謝謝
編輯:澄清一下,假設我有一個名為“CalculatorBrain”的類(如果這是正確的術語),下面的區別是什么(注意NSMutableArray * operandStack:
在.m文件中:
@interface CalculatorBrain()
@property (nonatomic, strong) NSMutableArray *operandStack;
@end
在.h文件中:
@interface CalculatorBrain : NSObject
@property (nonatomic, strong) NSMutableArray *operandStack;
@end
在我定義NSMutableArray *的地方有什么不同?
好的,在你澄清之后,我會試着解釋那里發生了什么。
假設你在標題(.h)文件中有這個:
@interface Foobar {
}
@property (readonly) int numberOfPies;
@end
這定義了一個類的公共接口。 雖然我在那里說過“公開”,但我想清楚地表明,Objective-C與Java或C ++沒有相同的可見性概念(它將它用於實例變量,但這是我最遠的。我知道了。 我也加粗了“階級”,因為有一個重要的區別即將到來。 我要指出的另一件事是,該類公開聲明numberOfPies
是readonly
,因為這也很重要。
現在,讓我們看看這個類的實現(.m)文件:
@interface Foobar ()
- (void) doSomething;
@property (readwrite) numberOfPies;
@end
@implementation Foobar
@synthesize numberOfPies;
- (void) doSomething {
NSLog(@"Doing something");
}
@end
看看@interface Foobar ()
- 這會開始一個類擴展 。 它不是一個類聲明。 這些也有時被稱為私有類別,匿名類別或類延續(根據下面評論中的zneak),但重要的是要知道它們基本上是一種類別 (我已經鏈接到Apple的類別文檔)。 這些基本上定義了其他方法和屬性,可以應用於任何類。 這里使用的是提供類的私有接口(因此是“私有類別”)。
繼續,現在我們將比較類和類別之間的numberOfPies
屬性。 如果您還沒有注意到差異,那么它就是:類將它公開為readonly
,類別擴展了它並使其在實現中進行readwrite
。 在合成屬性時,如果發生這種情況,Obj-C將同時包含getter和setter。 重要的是,除了您的財產是readonly
還是readwrite
,您的財產不能改變。 它不能在類中具有assign
屬性並在類別中進行copy
。 這基本上允許您為屬性定義方便的私有setter。
這里需要注意的一件重要事情是,該類別中絕對沒有任何內容真正屬於私人。 沒有什么能阻止你將doSomething
消息發送到Foobar
對象,盡管編譯器會在類的實現文件之外給你一個警告。
接下來,您將獲得標准實現。 這包括匿名類別中方法的實現。
Objective C類系統與Java不同 - 它將聲明和定義分開。 您可以在.h文件中定義屬性
@property(...) int X;
然后在.m文件中定義它的getter / setter(或合成)。 現在,您不必在.h中聲明它們。 類消費者仍然可以訪問它,但編譯器會向你發出警告“類可能不支持......”的效果。 這就是ObjC的動態性質。
另一方面,如果您聲明屬性但沒有定義/合成它,編譯器會抱怨您的類不完整。
該規則有一個例外。 如果未聲明該屬性但存在getter / setter / @ synthesize,則編譯器將允許您從類實現中使用它,從它在文件中定義的位置開始。 它與Java的私有訪問不同,因為該屬性仍然可以從類外部訪問(以警告為代價)。 這是最接近ObjC私人訪問的東西。
你只在@interface
聲明一個屬性。 你在@implementation
定義它。
聲明向客戶端或編譯器發布屬性存在,其類型和屬性。
定義是實際的實現。 沒有定義,實現將不存在。 也就是說,如果沒有定義,您可能會期望“不響應選擇器”異常。
這就像你在C中看到的那樣:
// only a declaration
int fun(void);
// a definition
int fun(void) {
...
}
但是你並不總是在ObjC上遇到鏈接器錯誤。
在我定義NSMutableArray *的地方有什么不同?
人們經常在類擴展中隱藏他們的一些聲明 (如在您的示例中),但它與可見性(例如public,protected,private)完全不同。 這些方法可能仍在外部調用,或者可以通過運行時(以及其他一些情況)訪問成員。 這是一種封裝嘗試,但它並不像你在其他語言(Java或C ++)中找到的那樣強大。
在C語言中,你通常編譯 .c
文件(或者,對於Objective-C中.m
文件,它們是類似的)一個接一個到本機代碼的斑點。 (這些blob是.o
文件。)編譯給定的.c
文件時,編譯器不會查看其他.c
文件以查看其中定義的函數。 您可以做的是,在鏈接時給出稍后可用的函數的編譯器聲明 (基本上是名稱和簽名)。
.h
文件基本上是這些聲明的列表。 它是.c
文件中可以在其他.c
文件中調用的所有函數(方法等)的清單。 因此,它通常應該只包括這些其他文件中所需的內容。 (“公共”功能。)
當.o
文件合並在一起時,構建C程序的第二階段是鏈接 ,並且它們之間的函數引用是連接的。
在Java中,您有.class
文件; 類文件包含類的方法的編譯器可讀簽名,以及它們的實現的字節碼。 與C類似的是,Java編譯器會自動提取將進入.h
文件的標頭,並將它們包含在.o
文件的開頭。
因為使用相同的工具鏈來構建兩種語言的程序,所以Objective-C繼承了普通C的這種分裂,包括拆分類的接口(“聲明”)及其在不同文件之間的實現(“定義”)。
(以上無疑是對C方式的粗略過度簡化,並且可以用非常不同的方式進行設置。我相信一個C文件到一個頭文件約定對於ObjC來說是相當傳統的。)
在“最純粹”的意義上,主要區別在於.h
文件應該包含在其他文件中,因此聲明的類成員意味着從外部可見; .m
文件並不意味着包含在任何地方,因此在那里聲明的任何東西都可能在其他任何地方都不可見。
與Java和其他流行語言相比,除非在使用之前聲明了全局符號(無論是類,結構,函數還是變量),否則無法訪問它。 這就是為什么在.m
文件中隱藏聲明使得從外部訪問符號變得更加困難的原因。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.