簡體   English   中英

Objective-C中的只讀屬性?

[英]Readonly Properties in Objective-C?

我在接口中聲明了一個readonly屬性,例如:

 @property (readonly, nonatomic, copy) NSString* eventDomain;

也許我誤解了屬性,但是我認為當您將其聲明為readonly ,可以在實現( .m )文件內部使用生成的setter,但是外部實體無法更改該值。 這樣的問題說那應該發生。 這就是我的行為。 但是,當嘗試使用標准的setter或點語法在我的init方法內部設置eventDomain ,它給了我一個unrecognized selector sent to instance. ,該unrecognized selector sent to instance. 錯誤。 當然,我正在@synthesize屬性。 嘗試像這樣使用它:

 // inside one of my init methods
 [self setEventDomain:@"someString"]; // unrecognized selector sent to instance error

那么我是否誤解了屬性的readonly聲明? 還是發生了其他事情?

您需要告訴編譯器您也想要一個setter。 一種常見的方法是將其放在.m文件的類擴展名中:

@interface YourClass ()

@property (nonatomic, copy) NSString* eventDomain;

@end

我發現使用只讀屬性的另一種方法是使用@synthesize指定后備存儲。 例如

@interface MyClass

@property (readonly) int whatever;

@end

然后在執行中

@implementation MyClass

@synthesize whatever = m_whatever;

@end

然后,您的方法可以設置m_whatever ,因為它是成員變量。


我在過去幾天中意識到的另一件有趣的事情是,您可以使只讀屬性可以被子類(例如:

(在頭文件中)

@interface MyClass
{
    @protected
    int m_propertyBackingStore;
}

@property (readonly) int myProperty;

@end

然后,在執行中

@synthesize myProperty = m_propertyBackingStore;

它將使用頭文件中的聲明,因此子類可以更新屬性的值,同時保留其只讀性。

遺憾的是,在數據隱藏和封裝方面。

Eiko和其他人給出了正確的答案。

這是一種更簡單的方法: 直接訪問私有成員變量。

在標題.h文件中:

@property (strong, nonatomic, readonly) NSString* foo;

在實施.m文件中:

// inside one of my init methods
self->_foo = @"someString"; // Notice the underscore prefix of var name.

就這樣,這就是您所需要的。 沒有糊塗,沒有大驚小怪。

細節

從Xcode 4.4和LLVM Compiler 4.0( Xcode 4.4中的新功能 )開始,您無需弄混其他答案中討論的瑣事:

  • synthesize關鍵字
  • 聲明一個變量
  • 在實現.m文件中重新聲明該屬性。

聲明屬性foo ,您可以假定Xcode添加了一個私有成員變量,其名稱下划線為_foo

如果將該屬性聲明為readwrite ,則Xcode會生成一個名為foo的getter方法和一個名為setFoo的setter。 當您使用點表示法(my Object.myMethod)時,將隱式調用這些方法。 如果將該屬性聲明為readonly ,則不會生成任何setter。 這意味着以下划線命名的后備變量本身不是只讀的。 readonly僅表示未合成任何setter方法,因此使用點表示法設置值會失敗,並出現編譯器錯誤。 點表示法失敗,因為編譯器阻止您調用不存在的方法(設置器)。

解決此問題的最簡單方法是直接訪問用下划線命名的成員變量。 即使沒有聲明下划線命名的變量,您也可以這樣做! Xcode會在構建/編譯過程中插入該聲明,因此您的編譯代碼實際上將具有變量聲明。 但是您永遠不會在原始源代碼文件中看到該聲明。 不是魔術,只是語法糖

使用self->是訪問對象/實例的成員變量的方法。 您也許可以省略它,而只需使用var名稱。 但是我更喜歡使用self + arrow,因為它可以使我的代碼自我記錄。 當您看到self->_foo您毫無疑問地知道_foo是此實例上的成員變量。


順便說一句,關於屬性訪問器與直接ivar訪問的優缺點的討論,正是您在Matt Neuberg博士的《 Programming iOS》一書中所讀到的。 我發現閱讀和重新閱讀非常有幫助。

請參閱iOS文檔中的自定義現有類

readonly指示該屬性為只讀。 如果指定只讀,則@implementation中僅需要getter方法。 如果在實現塊中使用@synthesize,則僅合成getter方法。 此外,如果嘗試使用點語法分配值,則會出現編譯器錯誤。

只讀屬性僅具有getter方法。 您仍然可以直接在屬性的類中或使用鍵值編碼來設置后備ivar。

您誤解了另一個問題。 在該問題中有一個類擴展,因此聲明為:

@interface MYShapeEditorDocument ()
@property (readwrite, copy) NSArray *shapesInOrderBackToFront;
@end

這就是生成只在類的實現中可見的setter的原因。 因此,正如Eiko所說的那樣,您需要聲明一個類擴展並重寫屬性聲明,以告訴編譯器僅在該類內生成setter。

最短的解決方案是:

MyClass.h

@interface MyClass {

  int myProperty;

}

@property (readonly) int myProperty;

@end

MyClass.h

@implementation MyClass

@synthesize myProperty;

@end

如果將一個屬性定義為只讀,則意味着實際上不會有可以在該類內部使用或在其他類外部使用的setter。 (即:只有這樣才可以使用“ getter”。)

從聲音上看,您需要一個普通的讀/寫屬性,將其標記為私有,可以通過在接口文件中將類變量設置為私有來實現,例如:

@private
    NSString* eventDomain;
}

暫無
暫無

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

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