[英]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
關鍵字 聲明屬性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.