Odpowiedzi:
właściwości mają określone znaczenie w Objective-C, ale myślę, że masz na myśli coś, co jest równoważne zmiennej statycznej? Np. Tylko jedna instancja dla wszystkich rodzajów Foo?
Aby zadeklarować funkcje klas w Objective-C, używasz przedrostka + zamiast - aby twoja implementacja wyglądała mniej więcej tak:
// Foo.h
@interface Foo {
}
+ (NSDictionary *)dictionary;
// Foo.m
+ (NSDictionary *)dictionary {
static NSDictionary *fooDict = nil;
if (fooDict == nil) {
// create dict
}
return fooDict;
}
.
Składnia -accessor nie jest związana z właściwościami w Objective-C, to po prostu skompilowane w skrótu dla każdej metody, która zwraca coś bez podejmowania jakichkolwiek args. W takim przypadku wolałbym to - osobiście wolę .
składnię dla każdego użycia, w którym kod klienta zamierza coś uzyskać, nie wykonywać akcji (nawet jeśli kod implementacyjny może utworzyć coś raz lub wykonać działania niepożądane) . Intensywne użycie .
składni powoduje również, że kod jest bardziej czytelny: obecność […]
s oznacza, że coś znaczącego jest robione, gdy pobieranie używa .
składni zamiast tego.
Korzystam z tego rozwiązania:
@interface Model
+ (int) value;
+ (void) setValue:(int)val;
@end
@implementation Model
static int value;
+ (int) value
{ @synchronized(self) { return value; } }
+ (void) setValue:(int)val
{ @synchronized(self) { value = val; } }
@end
Okazało się, że jest niezwykle przydatny jako zamiennik wzoru Singleton.
Aby z niego skorzystać, po prostu uzyskaj dostęp do swoich danych za pomocą notacji kropkowej:
Model.value = 1;
NSLog(@"%d = value", Model.value);
self
oznacza wewnątrz metody klasowej?
self
to obiekt, który otrzymał wiadomość . A ponieważ klasy są również obiektami , w tym przypadku self
oznaczaModel
@synchronized
?
Jak widać w WWDC 2016 / XCode 8 ( co nowego w sesji LLVM @ 5: 05). Właściwości klasy można zadeklarować w następujący sposób
@interface MyType : NSObject
@property (class) NSString *someString;
@end
NSLog(@"format string %@", MyType.someString);
Zauważ, że właściwości klasy nigdy nie są syntetyzowane
@implementation
static NSString * _someString;
+ (NSString *)someString { return _someString; }
+ (void)setSomeString:(NSString *)newString { _someString = newString; }
@end
static
zmienna ( ) musi być nadal zadeklarowana i używana, a metody jawnie zaimplementowane, tak jak poprzednio. Składnia kropkowa już wcześniej działała. W sumie brzmi to jak coś większego niż jest w rzeczywistości.
Jeśli szukasz ekwiwalentu klasy @property
, odpowiedź brzmi: „nie ma czegoś takiego”. Ale pamiętajcie @property
, w każdym razie to tylko cukier syntaktyczny; po prostu tworzy odpowiednio nazwane metody obiektowe.
Chcesz stworzyć metody klasowe, które uzyskują dostęp do zmiennych statycznych, które, jak powiedzieli inni, mają tylko nieco inną składnię.
UIDevice.currentDevice.identifierForVendor
pracuje dla mnie.
Oto bezpieczny sposób na zrobienie tego:
// Foo.h
@interface Foo {
}
+(NSDictionary*) dictionary;
// Foo.m
+(NSDictionary*) dictionary
{
static NSDictionary* fooDict = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
// create dict
});
return fooDict;
}
Te zmiany zapewniają, że fooDict jest tworzony tylko raz.
Z dokumentacji Apple : „dispatch_once - Wykonuje obiekt bloku raz i tylko raz na czas życia aplikacji”.
Initializer element is not a compile-time constant
.
Począwszy od Xcode 8 Objective-C obsługuje teraz właściwości klas:
@interface MyClass : NSObject
@property (class, nonatomic, assign, readonly) NSUUID* identifier;
@end
Ponieważ właściwości klas nigdy nie są syntetyzowane, musisz napisać własną implementację.
@implementation MyClass
static NSUUID*_identifier = nil;
+ (NSUUID *)identifier {
if (_identifier == nil) {
_identifier = [[NSUUID alloc] init];
}
return _identifier;
}
@end
Dostęp do właściwości klasy uzyskuje się za pomocą normalnej składni kropek na nazwie klasy:
MyClass.identifier;
Właściwości mają wartości tylko w obiektach, a nie w klasach.
Jeśli chcesz zapisać coś dla wszystkich obiektów klasy, musisz użyć zmiennej globalnej. Możesz to ukryć, deklarując static
w pliku implementacji.
Możesz także rozważyć użycie specyficznych relacji między swoimi obiektami: przypisujesz rolę wzorca konkretnemu obiektowi swojej klasy i łączysz inne obiekty z tym wzorcem. Mistrz zachowa słownik jako prostą właściwość. Myślę o drzewie takim jak to używane do hierarchii widoków w aplikacjach Cocoa.
Inną opcją jest utworzenie obiektu dedykowanej klasy, która składa się zarówno ze słownika „klasy”, jak i zestawu wszystkich obiektów związanych z tym słownikiem. To jest jak NSAutoreleasePool
w kakao.
Począwszy od Xcode 8, możesz użyć atrybutu właściwości class, na który odpowiedział Berbie.
Jednak w implementacji należy zdefiniować moduł pobierający i ustawiający klasę dla właściwości klasy za pomocą zmiennej statycznej zamiast iVar.
Próbka. H
@interface Sample: NSObject
@property (class, retain) Sample *sharedSample;
@end
Próbka.m
@implementation Sample
static Sample *_sharedSample;
+ ( Sample *)sharedSample {
if (_sharedSample==nil) {
[Sample setSharedSample:_sharedSample];
}
return _sharedSample;
}
+ (void)setSharedSample:(Sample *)sample {
_sharedSample = [[Sample alloc]init];
}
@end
Jeśli masz wiele właściwości na poziomie klasy, wzorzec singletonu może być w porządku. Coś takiego:
// Foo.h
@interface Foo
+ (Foo *)singleton;
@property 1 ...
@property 2 ...
@property 3 ...
@end
I
// Foo.m
#import "Foo.h"
@implementation Foo
static Foo *_singleton = nil;
+ (Foo *)singleton {
if (_singleton == nil) _singleton = [[Foo alloc] init];
return _singleton;
}
@synthesize property1;
@synthesize property2;
@synthesise property3;
@end
Teraz uzyskaj dostęp do swoich właściwości na poziomie klasy, takich jak to:
[Foo singleton].property1 = value;
value = [Foo singleton].property2;
dispatch_once
tutaj.
[Wypróbuj to rozwiązanie, to proste] Możesz utworzyć zmienną statyczną w klasie Swift, a następnie wywołać ją z dowolnej klasy Objective-C.