Po co zmieniać nazwy syntetyzowanych właściwości w iOS z wiodącymi podkreślnikami? [duplikat]
[4]} podczas tworzenia nowego projektu w Xcode 4, Kod boilerplate dodaje znak podkreślenia, gdy syntetyzuje ivars w pliku implementacji jako:Możliwy duplikat:
Jak działa podkreślenie przed zmienną w klasie Cocoa objective-c?
@synthesize window = _window;
Lub:
@synthesize managedObjectContext = __managedObjectContext;
Czy ktoś może mi powiedzieć, co tu się osiąga? Nie jestem kompletnym nube, ale to jest jeden aspekt objective-C, którego nie rozumiem.
Kolejny punkt zamieszania; w implementacji delegata aplikacji, po zsyntetyzowaniu window iVar jak powyżej, w metodzie didFinishLaunchingWithOptions: do ivarów window I viewController odnoszą się używając self:
self.window.rootViewController = self.viewController
[self.window makeKeyAndVisible];
Ale w metodzie dealloc jest to _window lub _viewController
Thanks
4 answers
Jest to artefakt poprzedniej wersji runtime Objective-C.
Pierwotnie, @synthesize
było używane do tworzenia metod dostępu, ale runtime nadal wymagało, aby zmienne instancji musiały być bezpośrednio utworzone:
@interface Foo : Bar {
Baz *_qux;
}
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
@end
Ludzie określaliby swoje zmienne instancji, aby odróżnić je od ich właściwości (nawet jeśli Apple nie chce, abyś używał podkreślników, ale to inna sprawa). Można zsyntetyzować właściwość, aby wskazać zmienną instancji. Chodzi jednak o to, że _qux
jest zmienną instancyjną, a self.qux
(lub [self qux]
) jest wiadomością qux
wysłaną do obiektu self
.
Używamy zmiennej instancji bezpośrednio w -dealloc
; użycie metody accessor zamiast tego wyglądałoby tak (choć nie polecam jej, z powodów wyjaśnię krótko):
- (void)dealloc {
self.qux = nil; // [self setQux:nil];
[super dealloc];
}
Powoduje to zwolnienie qux
, a także zerowanie odniesienia. Ale to może mieć niefortunne skutki uboczne:
- możesz skończyć strzelając nieoczekiwane powiadomienia. Inne obiekty mogą obserwować zmiany
qux
, które są rejestrowane, gdy do ich zmiany używana jest metoda accessora. - (nie wszyscy się z tym zgadzają:) Zerowanie wskaźnika tak, jak robi to accessor, może ukryć błędy logiczne w twoim programie. Jeśli kiedykolwiek uzyskujesz dostęp do zmiennej instancji obiektu po obiekt został dealokowany, robisz coś poważnie złego. Ze względu na semantykę Objective-C
nil
- messaging, będziesz nigdy nie wiadomo, po użyciu accesora do Ustawienia nanil
. Gdybyś zwolnił zmienną instancyjną bezpośrednio i nie wyzerował referencji, dostęp do dealokowanego obiektu spowodowałby głośnyEXC_BAD_ACCESS
.
Późniejsze wersje runtime dodały możliwość syntezy zmiennych instancji oprócz metod accessora. W tych wersjach runtime powyższy kod można zapisać pomijając zmienne instancji:
@interface Foo : Bar
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
@end
To rzeczywiście syntetyzuje instancję zmienna na Foo
o nazwie _qux
, do której dostęp mają komunikaty getter i setter -qux
i -setQux:
.
Polecam przed tym: JEST Trochę bałagan, ale jest jeden dobry powód, aby użyć podkreślenia; a mianowicie, aby chronić przed przypadkowym bezpośrednim dostępem ivar. Jeśli uważasz, że możesz sobie zaufać, że zapamiętasz, czy używasz surowej zmiennej instancji, czy metody accessora, zrób to w ten sposób:
@interface Foo : Bar
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux;
- (void)dealloc {
[qux release];
[super dealloc];
}
@end
Wtedy, gdy chcesz uzyskać bezpośredni dostęp do zmiennej instancji, po prostu powiedz qux
(co tłumaczy się na self->qux
w składni C, aby uzyskać dostęp do elementu ze wskaźnika). Jeśli chcesz korzystać z metod accessors (które będą powiadamiać obserwatorów i robić inne ciekawe rzeczy, a także uczynić rzeczy bezpieczniejszymi i łatwiejszymi w zakresie zarządzania pamięcią), użyj self.qux
([self qux]
) oraz self.qux = blah;
([self setQux:blah]
).
Smutne jest to, że przykładowy kod Apple ' a i kod szablonu są do bani. Nigdy nie używaj go jako przewodnika po właściwym stylu Objective-C, a na pewno nigdy nie używaj go jako przewodnika po właściwym Architektura oprogramowania. :)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-13 17:54:46
Jest jeszcze jeden powód. Bez podkreślenia zmiennych instancji często otrzymuje się ostrzeżenie o parametrach self.title = title
i self.rating = rating
:
@implementation ScaryBugData
@synthesize title;
@synthesize rating;
- (id)initWithTitle:(NSString *)title rating:(float)rating {
if (self = [super init]) {
self.title = title; // Warning. Local declaration hides instance variable
self.rating = rating; // Warning. Local declaration hides instance variable
}
return self;
}
@end
Unikasz Ostrzeżenia, podkreślając zmienne instancji:
@implementation ScaryBugData
@synthesize title = _title;
@synthesize rating = _rating;
- (id)initWithTitle:(NSString *)title rating:(float)rating {
if (self = [super init]) {
self.title = title; // No warning
self.rating = rating; // No warning
}
return self;
}
@end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-07 15:17:59
Nie, Nie są. Są to odniesienia do właściwościW aplikacji didFinishLaunchingWithOptions: method do ivarów window i viewController odnoszą się za pomocą self
window
i viewController
. To jest punkt podkreślenia, aby wyjaśnić, kiedy właściwość jest używana (bez podkreślenia) i kiedy ivar jest dostępny bezpośrednio (z podkreśleniem).Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-29 00:25:06
Tak, Its jest tylko po to, aby odróżnić odniesienie do obiektu. Oznacza to, że jeśli obiekt jest bezpośrednio referowany, użyj go z podkreśleniem, w przeciwnym razie użyj self, aby odnieść się do obiektu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-30 04:38:40