簡體   English   中英

在Objective-C API中安全更改和使用只讀屬性值

[英]Safe mutation and usage of readonly property value in Objective-C APIs

考慮像const T* foo()這樣的C ++ API。 這清楚地記錄了API的受支持的可變性和使用: 好的,我們讓您看一下T,但是請不要更改它 您仍然可以對其進行變異,但是您必須顯式使用const_cast來表明您打算不遵循API。

Objective-C API的很大一部分由屬性聲明組成。 API的用戶應如何解釋@property (readonly) T foo (假設T不是一成不變的類型)

  • 由於二傳手不是合成的,因此顯然foo並不意味着被替換
  • 但是,getter仍然給我一個指向foo的指針。 變異foo是否安全? (顯然我可以

注意:我不是在詢問語言規格。 我問的是,Objective-C社區中對此類API的常規解釋是什么。

正如matt所說的,您擁有指向該對象的指針的事實並不意味着該對象本身是可變的。 Objective-C使用類的行為而不是指針來實施不變性。 因此,通常您應該看到返回的只讀屬性,例如NSString而不是NSMutableString

我瀏覽了Apple的iOS框架標頭以驗證這一點:

grep -rn "@property.*readonly.*Mutable" /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/*.h

(可可中類名稱的模式是調用$PREFIXMutable$CLASSNAME類的可變“版本”: NSString / NSMutableStringNSDictionary / NSMutableDictionary 。)

./System/Library/Frameworks/AVFoundation.framework/Headers/AVComposition.h:133:@property(非原子,只讀)NSArray <AVMutableCompositionTrack *> * tracks; ./System/Library/Frameworks/CoreData.framework/Headers/NSManagedObjectContext.h:149:@property(非原子,只讀,強)NSMutableDictionary * userInfo NS_AVAILABLE(10_7,5_0); ./System/Library/Frameworks/Foundation.framework/Headers/NSAttributedString.h:54:@property(只讀,保留)NSMutableString * mutableString; ./System/Library/Frameworks/Foundation.framework/Headers/NSExpression.h:127:@property(只讀,復制)id(^ expressionBlock)(id __nullable,NSArray *,NSMutableDictionary * __nullable)NS_AVAILABLE(10_6,4_0); ./System/Library/Frameworks/Foundation.framework/Headers/NSThread.h:24:@property(只讀,保留)NSMutableDictionary * threadDictionary; ./System/Library/Frameworks/GameplayKit.framework/Headers/GKRuleSystem.h:54:@property(非原子,保留,只讀)NSMutableDictionary * state; ./System/Library/Frameworks/ModelIO.framework/Headers/MDLMesh.h:137:@property(非原子,只讀,保留)NSMutableArray *子網格;

只有七個結果, NSExpression中的一個不計算在內,因為搜索找到的“ Mutable”是Block的一個參數,實際上是該屬性的值。

對於其他人,我認為您會發現適當的類引用文檔會告訴您可以使用和不能使用值的內容。

例如, threadDictionary文檔說明如下:

您可以使用返回的字典來存儲特定於線程的數據。[...]您可以為字典定義自己的鍵。

可變字典會精確返回,以便您對其進行突變。 但是,線程對象不允許您對其進行設置,因此它也可以在其中存儲內容。

NSAttributedString.h中的命中實際上在NSMutableAttributedString類中, 這些文檔指出

接收者跟蹤對此字符串的更改,並保持其屬性映射為最新。

由於NSAttributedString非常明顯*,只是一個NSString打包了許多屬性,因此類的設計直接公開了包裝的字符串; 可變版本也是如此。

注釋中提到了UIButton ,因為那里有一個只讀標簽,其自身屬性可以修改。 同樣, 文檔是顯式的

盡管此屬性是只讀的,但它自己的屬性是讀/寫。 主要使用這些屬性來配置按鈕的文本。

不要使用標簽對象設置文本顏色或陰影顏色。

總而言之,Objective-C在語言級別上無法創建或強制實施可變性限制。 正如您已經指出的,標記為readonly的屬性只是意味着您無法將值設置為其他值。**而且沒有const_cast將該值設置為可變的以便您可以更改它:您將最終得到具有供應商對象一無所知的新值。

因此, 可可約定是通過使用不可變類來第二次增強財產的地位。 (在某些情況下,您甚至可能會獲得該類在內部保留為可變的數據的不可變副本。)如果API為您提供了可變的對象,則可以假定您可以對其進行突變,但是文檔應該確切地告訴您如何可以使用它


*其類描述說 :“ NSAttributedString對象管理字符串以及應用於字符串中各個字符或字符范圍的關聯屬性集(例如,字體和字距調整)。”

**有KVC,但這又是在框架級別,框架約定將表明您在這樣做時遇到麻煩。

暫無
暫無

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

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