W moim interfejsie zadeklarowałem właściwość tylko do odczytu:
@property (readonly, nonatomic, copy) NSString* eventDomain;
Może nie rozumiem właściwości, ale pomyślałem, że kiedy deklarujesz je jako readonly
, możesz użyć wygenerowanego setera w .m
pliku implementacji ( ), ale zewnętrzne jednostki nie mogą zmienić wartości. To pytanie SO mówi, że tak powinno się stać. To jest zachowanie, którego szukam. Jednak przy próbie użycia metody ustawiającej standard lub składni kropki do ustawienia eventDomain
wewnątrz mojej metody init powoduje to unrecognized selector sent to instance.
błąd. Oczywiście, że jestem @synthesize
właścicielem. Próbuję tego użyć w ten sposób:
// inside one of my init methods
[self setEventDomain:@"someString"]; // unrecognized selector sent to instance error
Czy więc źle rozumiem readonly
oświadczenie dotyczące nieruchomości? A może dzieje się coś innego?
.h
? W przeciwnym razie nie widzę, jak mogłoby to ujawnić publicznego ustawiacza. DziękiEiko i inni udzielili poprawnych odpowiedzi.
Oto prostszy sposób: bezpośredni dostęp do prywatnej zmiennej składowej.
Przykład
W pliku nagłówkowym .h:
@property (strong, nonatomic, readonly) NSString* foo;
W pliku .m implementacji:
// inside one of my init methods self->_foo = @"someString"; // Notice the underscore prefix of var name.
To wszystko, to wszystko, czego potrzebujesz. Bez musów, bez zamieszania.
Detale
Począwszy od Xcode 4.4 i LLVM Compiler 4.0 ( nowe funkcje w Xcode 4.4 ), nie musisz zadzierać z obowiązkami omówionymi w innych odpowiedziach:
synthesize
kluczowePo zadeklarowaniu właściwość
foo
, można założyć, Xcode dodała prywatną zmienną składową o nazwie z prefiksem podkreślenia:_foo
.Jeśli właściwość została zadeklarowana
readwrite
, Xcode generuje metodę pobierającą o nazwiefoo
i metodę ustawiającą o nazwiesetFoo
. Te metody są wywoływane niejawnie, gdy używasz notacji z kropką (my Object.myMethod). Jeśli właściwość została zadeklarowanareadonly
, nie jest generowany żaden ustawiający. Oznacza to, że zmienna zapasowa, nazwana podkreśleniem, sama nie jest tylko do odczytu. Tereadonly
środki, które po prostu nie sposób seter został zsyntetyzowany, a więc za pomocą notacji kropki ustawić wartość nie z błędu kompilatora. Notacja z kropką kończy się niepowodzeniem, ponieważ kompilator powstrzymuje Cię przed wywołaniem metody (ustawiającej), która nie istnieje.Najprostszym sposobem obejścia tego jest bezpośredni dostęp do zmiennej składowej, nazwanej podkreśleniem. Możesz to zrobić nawet bez deklarowania zmiennej o nazwie podkreślonej! Xcode wstawia tę deklarację jako część procesu kompilacji / kompilacji, więc skompilowany kod rzeczywiście będzie zawierał deklarację zmiennej. Ale nigdy nie widzisz tej deklaracji w swoim oryginalnym pliku kodu źródłowego. Nie magia, tylko cukier syntaktyczny .
Używanie
self->
to sposób na dostęp do zmiennej składowej obiektu / instancji. Możesz to pominąć i po prostu użyć nazwy var. Ale wolę używać self + arrow, ponieważ sprawia, że mój kod jest samodokumentujący. Gdy zobaczysz,self->_foo
że wiesz bez niejasności,_foo
jest to zmienna składowa w tej instancji.Nawiasem mówiąc, omówienie zalet i wad udostępniające właściwości w porównaniu bezpośrednim dostępem Ivar jest dokładnie ten rodzaj przemyślany leczenia będziesz czytać w dr Matt Neuberg „s Programowanie iOS książki. Przeczytanie i ponowne przeczytanie okazało się bardzo pomocne.
źródło
readonly
takiej, aby żadna inna klasa nie mogła jej ustawić.Innym sposobem pracy z właściwościami tylko do odczytu jest użycie @synthesize do określenia magazynu zapasowego. Na przykład
@interface MyClass @property (readonly) int whatever; @end
Następnie w realizacji
@implementation MyClass @synthesize whatever = m_whatever; @end
Twoje metody mogą następnie ustawić
m_whatever
, ponieważ jest to zmienna składowa.Inną interesującą rzeczą, z której zdałem sobie sprawę w ciągu ostatnich kilku dni, jest to, że możesz tworzyć właściwości tylko do odczytu, które są zapisywalne przez podklasy, takie jak:
(w pliku nagłówkowym)
@interface MyClass { @protected int m_propertyBackingStore; } @property (readonly) int myProperty; @end
Następnie w trakcie realizacji
@synthesize myProperty = m_propertyBackingStore;
Użyje deklaracji w pliku nagłówkowym, więc podklasy mogą aktualizować wartość właściwości, zachowując jej tylko do odczytu.
Nieco niestety, jeśli chodzi o ukrywanie i hermetyzację danych.
źródło
Zobacz Dostosowywanie istniejących klas w dokumentach iOS.
Właściwości tylko do odczytu mają tylko metodę pobierającą. Nadal można ustawić zapasowy ivar bezpośrednio w klasie właściwości lub za pomocą kodowania wartości klucza.
źródło
Nie rozumiesz drugiego pytania. W tym pytaniu istnieje rozszerzenie klasy, zadeklarowane w ten sposób:
@interface MYShapeEditorDocument () @property (readwrite, copy) NSArray *shapesInOrderBackToFront; @end
To właśnie generuje ustawiacz widoczny tylko w implementacji klasy. Tak więc, jak mówi Eiko, musisz zadeklarować rozszerzenie klasy i przesłonić deklarację właściwości, aby poinstruować kompilator, aby generował metodę ustawiającą tylko w klasie.
źródło
Najkrótszym rozwiązaniem jest:
MyClass.h
@interface MyClass { int myProperty; } @property (readonly) int myProperty; @end
MyClass.h
@implementation MyClass @synthesize myProperty; @end
źródło
Jeśli właściwość jest zdefiniowana jako tylko do odczytu, oznacza to, że faktycznie nie będzie metody ustawiającej, której można by użyć wewnętrznie do klasy lub zewnętrznie z innych klas. (tj. będziesz mieć „getter” tylko wtedy, gdy ma to sens).
Z dźwięków tego wynika, że chcesz mieć normalną właściwość odczytu / zapisu, która jest oznaczona jako prywatna, co można osiągnąć, ustawiając zmienną klasy jako prywatną w pliku interfejsu jako taką:
@private NSString* eventDomain; }
źródło