2013-11-14 89 views
5

對我來說,Objective-C開發人員的過去很簡單。一個類需要公開的每個字段都是一個屬性,每個私有字段都是一個沒有getter或setter的實例變量。但更常見的是,我看到人們在實現文件中使用私有接口來聲明私有屬性。我被告知這是現在做事情的方式。Objective-C:私有變量VS私有屬性

雖然這工作正常,但我很難看到優勢。只要我不需要getter或setter中的某些邏輯,我就會繼續使用實例變量來處理一切不公開的事情。我不得不承認使用一個屬性,然後使用關鍵字self使代碼更具可讀性。你可以看到一個屬性是屬於這個類還是它只是一個方法中的局部變量,但這不是唯一的原因。

爲什麼或爲什麼不使用私有財產?

+0

請參閱http://stackoverflow.com/questions/5615695/best-way-of-declaring-private-variables-in-cocoa和http://stackoverflow.com/questions/17575119/private-properties-vs-實例變量在弧 – Rob

回答

0

objective-c中的屬性是而不是只是實例變量。它們是由實例變量支持的getter和setter方法的組合。

通常當人們在實現文件(私有類擴展名)中添加屬性時,它會公開創建一個屬性屬性,以便它們可以設置它並保留所有屬性語義,如鍵值編碼。屬性也照顧你的複製保留。

它只是一個保持你的公共接口與實現分開的方法。

+1

我覺得OP明白這一點。 – DrummerB

+0

好點@ readonly/readwrite。 – DrummerB

+1

您可以擁有一個只讀的公共屬性,並在實施中直接設置伊娃。你不需要私人的讀/寫屬性。 – rmaddy

7

有幾個原因使用(私人)屬性而不是ivars。

  • 正如你所說,使用屬性將允許您輕鬆使用除訪問變量之外還執行一些額外編碼的訪問器方法。
  • KVO不適用於ivars。
  • 只爲實施做一個公共只讀屬性讀寫,除了getter之外還有一個合成器(正如Brad指出的那樣)
  • 個人喜好,習慣或懶惰(財產是公開的,但被改爲私有)。
+2

+1我想添加到這個列表中,使用屬性也避免了需要擔心內存語義,因爲它是由setter決定的(例如,如果你有一個'copy'屬性,每次調用setter時,它都會自動爲您複製該對象,而不是每次設置實例變量時都需要記住顯式調用'copy')。此外,這也是KVC評論的必然結果,但我認爲它簡化了與「NSCoding」(例如歸檔時有用)和「NSCopying」(儘管顯然,您不需要執行這些協議的屬性)的一致性。 – Rob

+0

我同意你關於KVO,但是是什麼讓你說* KVC *不適用於ivars? – jlehr

+0

你說得對,我的錯。我更新了我的答案,謝謝。 – DrummerB

1

首先,如果你不需要的私人財產,不使用屬性:除非你想從編譯器的一些具體行爲的聲明,例如強制執行任務NSString複製,沒有使用任何好處屬性。

此外,您不一定需要使用self才能訪問這些屬性:當您自動或通過@synthesize關鍵字合成屬性時,會得到一個「備份」屬性的變量。指定該變量是訪問屬性的完全合法的方式,例如,當您想將其呈現爲只讀時。

但是,它的優勢,使得這些私有變量,即在一個類擴展聲明它們,就像這樣:

@interface MyClass() { // <<== Note the() -- it's a class extension 
    SomeOtherClass *privateIvar; 
} 

如果您在聲明一個類擴展(可變它出現在.m文件而不是標題),那麼您可以隱藏"SomeOtherClass"的標題,這對開發單個應用程序並不重要,但在您開始使用自己的類庫開發時變得非常有用。

-1

這很簡單。

如果你想使用私人@property,添加您的m內這個屬性:

@interface MyViewController() 

@property (nonatomic, strong) NSString *myPrivateStringProperty; 

@end 

@implementation MyViewController 

@end 

這裏,屬性是隻在您的m訪問。

如果你想使用公共@property,添加您的.h這裏面的屬性:

@interface MyViewController : UIViewController 

@property (nonatomic, strong) NSString *myPublicStringProperty; 

@end 

這裏,屬性是類的外部訪問。

+1

我不認爲問題是「如何做私人與公共財產?」,而是「爲什麼私人財產,而不是私人實例變量?」。 – Rob

+0

所以,我不明白對不起:( –

+1

你似乎在描述如何使一個財產私人與公開。但我不認爲這是問題。問題是是否有任何優勢使用私有屬性,而不是僅僅定義一個私有實例變量(沒有關聯的屬性),並直接使用該私有實例變量 – Rob

0

這僅僅是一個封裝你可以有許多不同的層面的私有化的事情......

最初在Objective-C運行時不支持在運行時的對象添加實際的領域,所以每伊瓦爾曾在課堂上列出:

@interface MyClass : NSObject 
{ 
//every ivar that MyClass adds to NSObject must be here 
} 

這是一個簡單的和足夠好的系統,一會兒......

甚至私人的ivars不得不宣佈,雖然編譯器不會讓你訪問他們錯了範圍。

@interface MyClass : NSObject 
{ 
@private 
id someObj; 
} 

這種可見性說明符的機會有限,如:

//someotherclass.m

+ (void)doSomething 
{ 
    MyCLass * mc = [MyClass new]; 
    mc->someObj = [SomeOtherClass new]; // error cant access private variable... 
} 

,但你可能會得到它與指針arithmatic,所以混淆,你會看到這樣的事情在類:

@interface MyClass : NSObject 
{ 
@private 
void * __reserved1; 
void * __private1; 
} 

這是相當不錯的混淆...

但等等...... 有一個更好的方法!

進入非脆弱ABI

現在類只需要導出他們的超類和公共接口。

@interface MyClass : NSObject 
@property (readonly,retain) id someIVar; 

和類中的其他內容,可以包含在類擴展:

@interface MyClass() 
{ 
id someObj; 
} 
@property (readwrite,retain) id someIVar; 

提防,這將僅適用於iPhone和64位OS X 32位OS X的工作仍然是舊的ABI和需要在那裏工作的圖書館將需要以前的方式。

+0

這與在運行時創建的ivars無關,它們是編譯器在編譯時創建的。 – zaph

+0

它們可以在編譯時創建,但是它們是以動態方式創建的,因此無法確定它們的偏移量。 –

0

那麼使用屬性可能會更「方便」(至少因爲您不必擔心在具有KVO屬性的情況下會調用willChange/didChange),毫無疑問,使用ivars代替屬性會更快。所以我會建議使用屬性,除非你真的關心每秒幀數。如果是這種情況,請查看this awesome post

1

IMO OP在詢問爲什麼要在界面中放置一些ivars,並在實施中放置一些ivars。一個側面的問題是爲什麼屬性。

  1. 重點是封裝。只將這些東西放在公共接口(.h)文件中,這些文件應該在課堂以外的設計中使用。將那些僅由設計人員使用的實現(.m)文件中的實現。這是沒有公開的任何內容都可以在以後更改,而不會影響課程的用戶。

  2. 屬性爲關聯的ivars提供setter/getter方法。在當前的Objective-C編譯器中,如果沒有@synthesize語句,編譯器將自動生成與前綴爲下劃線(_)的屬性具有相同名稱的ivar。 getter/setter也支持KVO,根據您的使用情況,這可能是一個加號。請注意,可以在接口文件中聲明一個屬性,並在實現文件類擴展中讀寫。

因此,目前最好的做法是使用性質的所有實例變量,並把財產陳述無論是在接口文件,如果它們被設計爲公共或在一類擴展實現文件,如果它們被設計是私人的。這提供了一個乾淨的接口文件,只公開公共方法和屬性。