簡體   English   中英

Objective-C 中的私有屬性和方法

[英]Private properties and methods in Objective-C

在查看 Apple 的一個示例時,在 TableViewController.m 中,他們有這個:

// Private TableViewController properties and methods.
@interface TableViewController ()

@property (nonatomic, retain) NSMutableArray* sectionInfoArray;
@property (nonatomic, retain) NSIndexPath* pinchedIndexPath;
@property (nonatomic, assign) NSInteger openSectionIndex;
@property (nonatomic, assign) CGFloat initialPinchHeight;
... more properties and methods
@end

@implementation TableViewController
... usual stuff

我想知道他們為什么將這些屬性放在 .m 文件中,以及它是如何私有的。 似乎任何導入 TableViewController.m 文件的人都可以使用這些屬性和方法,對吧? 為什么不在.h 文件中使用@private?

他們所做的是在 class 上聲明一個類別,但由於這是在 .m 文件中完成的,因此這些方法是“不可見的”。

然而,這並不意味着不能從外部調用這些方法。 這是因為目標 c 中沒有真正的隱私,因為我們處理的是消息,而不是方法調用。 這意味着您可以向 object 發送消息,即使您不知道 object 是否實際實現了您嘗試調用的方法。 接收 object 將在運行時確定它是否可以處理此調用,甚至可能會轉發它,並且調用 object 是否知道該方法沒有區別。

這就是為什么可以調用私有 API 並因此被拒絕的原因之一。

AFAIK

a) 您不能將屬性標記為 @private in.h - 這僅適用於 ivars。

b) 如果您只是 import.m 文件(在.h 文件中沒有接口定義),您將無法引用您的 class。 如果你這樣做 - 你會在鏈接過程中得到重復的符號。

c)所以是的,這些屬性是私有的,因為它們不能作為常規屬性從外部訪問 - 這些屬性只能使用顯式消息訪問 - 但是在這種情況下你會收到編譯器的警告,或者你可以使用 KVC

他們不是私人的。 它們是匿名屬性,因為它們是匿名類別的一部分。

屬性的好處之一是將擁有的 object 的 memory 管理語義放在一個地方。 考慮一下:

@property (nonatomic, assigned) NSString *assigned;
@property (nonatomic, copy) NSString *copied;
@property (nonatomic, retain) NSString *retained;

在這三種情況下,您可以像這樣分配它們,而無需知道它們的 memory 語義是什么:

self.assigned = stringParameter; // assigns to instance variable
self.copied = stringParameter; // copies, assigns copy to instance variable
self.retained = stringParameter; // retains, assigns to instance variable

在所有三種情況下,您都可以使用相同的代碼進行免費清理:

self.assigned = nil; // this just nils the instance variable
self.copied = nil; // releases copy in ivar, nils instance variable
self.retained = nil; // releases ivar (same as original object),
                     // nils instance variable

這就是為什么您經常會看到本地屬性:它讓編碼人員在每次想要分配給實例變量時跳過編寫所有 memory 管理邏輯。 這是一個主要優勢,因為您只需更改 @property 即可在整個 class 中更改@property管理邏輯。

匿名屬性的另一個用途是將聲明為只讀的屬性擴展到外部代碼,以對 class 本身進行讀/寫

在.h:

@property (nonatomic, readonly, retain) NSError *lastError;

In.m,在匿名類別中:

@property (nonatomic, readwrite, retain) NSError *lastError;

在.m代碼的其他地方:

self.lastError = error;

同樣,這主要是出於 memory 管理原因。

一個例子,與使用匿名屬性有關。

以下是沒有屬性的 _lastError 實例變量的每個賦值。

假設我們在 .h 文件中定義了一個名為 _lastError 的 NSError。

保留:

[_lastError release];
_lastError = [error retain];

帶副本:

[_lastError release];
_lastError = [error copy];

分配:

_lastError = error;

在前兩種情況下,您需要在您的 dealloc 中使用它:

[_lastError release];

但在最后一種情況下,你必須在 dealloc 中不放任何東西,否則你會崩潰。

因此,讓我們添加我們需要使用屬性的內容:

將此添加到匿名類別中:

@property (nonatomic, readwrite, retain) NSError *lastError;

在@implementation 中添加:

@synthesize lastError = _lastError;

另請注意,此時在“現代”Cocoa 運行時(64 位 Mac 或 iOS)上,您可以從 header 中刪除 NSError *_lastError。 編譯器可以根據@synthesize 找出你想要的。

以下是它如何改變我們的代碼:

每個任務:

self.lastError = error; // works regardless of storage specifier

在代洛克:

self.lastError = nil; // works regardless of storage specifier

首先,您通常不能導入一個 .m 文件 - 並非沒有大量編譯器/鏈接器錯誤。 其次,這些屬性是私有的,因此 Apple 可以在后續版本中自由更改它們。

是的,您可以通過反射找到它們。 但這是一個滑坡,等等等等,后果自負,除非你確切地知道自己在做什么,否則會在以后的版本中中斷等等等等。

目標 c 中沒有私有方法或變量,@private 標志主要在那里,所以當其他開發人員查看它時,他們知道它應該是私有的。 你在蘋果代碼中看到的是一個類別的例子,一種在目標 c 中偽造私有方法和變量的方法。 因為外部類只會導入 .h 文件,所以他們永遠不會看到 .m 文件中添加的方法和變量。

使用匿名類別黑盒其他類不應該知道的內部屬性和方法。 盡管當從其他類引用此 class 時編譯器不知道它們,但從技術上講,您可以使用鍵值編碼從其他 class 訪問這些屬性中的任何一個。

不能導入實現文件TableViewController.m ,只能導入TableViewController.h文件,

雖然,您可以在TableViewController class 之外引用這些屬性,並帶有顯示“未響應”注釋的警告。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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