簡體   English   中英

在Objective-C中,在頭文件中定義某些東西(比如屬性)與.m文件相比有什么區別?

[英]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 ++沒有相同的可見性概念(它將它用於實例變量,但這是我最遠的。我知道了。 我也加粗了“階級”,因為有一個重要的區別即將到來。 我要指出的另一件事是,該類公開聲明numberOfPiesreadonly ,因為這也很重要。

現在,讓我們看看這個類的實現(.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM