2009-03-30 10 views

risposta

177

proprietà hanno un significato specifico in Objective-C, ma penso che tu intenda qualcosa che è equivalente a una variabile statica? Per esempio. solo una istanza per tutti i tipi di Foo?

Dichiarare funzioni di classe in Objective-C si utilizza il prefisso +, invece di - così l'implementazione sarebbe simile:

// Foo.h 
@interface Foo { 
} 

+ (NSDictionary *)dictionary; 

// Foo.m 
+ (NSDictionary *)dictionary { 
    static NSDictionary *fooDict = nil; 
    if (fooDict == nil) { 
    // create dict 
    } 
    return fooDict; 
} 
+1

Qualche idea sul motivo per cui ciò potrebbe causare un'eccezione BAD ACCES? Sto caricando un UITableView e il primo lotto carica bene ma nello scorrimento ottieni BADACCES. – mamcx

+0

Dovresti incollare il tuo codice. È importante ricordare che per impostazione predefinita UITableView riutilizza le celle durante lo scorrimento se hanno lo stesso identificatore. –

+20

È giusto? Non imposterà fooDict su zero dato che la prima riga del metodo dizionario porta sempre a ricreare il dizionario ogni volta? – PapillonUK

62

Se stai cercando per il a livello di classe equivalente di @property, poi la risposta è "non esiste una cosa del genere". Ma ricorda, lo @property è comunque solo zucchero sintattico; crea solo metodi oggetto con nome appropriato.

Si desidera creare metodi di classe che accedono a variabili statiche che, come altri hanno detto, hanno solo una sintassi leggermente diversa.

+0

Anche le proprietà pensiero sono sintattiche Sarebbe comunque bello poter utilizzare la sintassi del punto per elementi come MyClass.class anziché [classe MyClass]. –

+4

@ZakyGerman Puoi! 'UIDevice.currentDevice.identifierForVendor' funziona per me. –

+1

@tc. Grazie! Riempimento stupido ora. Per qualche ragione, ero convinto di averlo provato in passato, ma non ha funzionato.È una novità per caso? –

7

Le proprietà hanno valori solo negli oggetti, non nelle classi.

Se è necessario memorizzare qualcosa per tutti gli oggetti di una classe, è necessario utilizzare una variabile globale. Puoi nasconderlo dichiarandolo static nel file di implementazione.

Si può anche considerare l'utilizzo di relazioni specifiche tra gli oggetti: si attribuisce un ruolo di maestro a un oggetto specifico della classe e si collegano altri oggetti a questo master. Il master terrà il dizionario come una proprietà semplice. Penso ad un albero come quello usato per la gerarchia delle viste nelle applicazioni Cocoa.

Un'altra opzione è creare un oggetto di una classe dedicata che sia composta sia dal dizionario di 'classe' sia da un insieme di tutti gli oggetti relativi a questo dizionario. Questo è qualcosa come NSAutoreleasePool in Cocoa.

98

sto usando questa soluzione:

@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 

e l'ho trovato estremamente utile in sostituzione di pattern Singleton.

Per utilizzarlo, è sufficiente accedere ai dati con la notazione punto:

Model.value = 1; 
NSLog(@"%d = value", Model.value); 
+3

Questo è davvero fantastico. Ma cosa diavolo significa "sé" all'interno di un metodo di classe? –

+8

@ToddLehman 'self' è [l'oggetto che ha ricevuto il messaggio] (https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithObjects/WorkingwithObjects.html#//apple_ref/doc/ uid/TP40011210-CH4-SW5). E poiché [le classi sono anche oggetti] (https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/DefiningClasses/DefiningClasses.html#//apple_ref/doc/uid/TP40011210-CH3-SW18), in questo caso 'self' significa' Modello' – spooki

+3

Perché il getter deve essere '@ sincronizzato'? –

19

Ecco un filo modo sicuro di farlo:

// 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; 
} 

Queste modifiche assicurano che fooDict viene creato solo una volta.

Da Apple documentation: "dispatch_once - Esegue un oggetto blocco una sola volta per la durata di un'applicazione."

+2

Il codice dispatch_once non è irrilevante poiché un NSDictionary statico può essere inizializzato sulla prima riga del metodo di dizionario + (NSDictionary *) e poiché è statico, verrà inizializzato solo una volta? – jcpennypincher

+0

@jcpennypincher Tentare di inizializzare il dizionario sulla stessa riga della sua dichiarazione statica produce il seguente errore del compilatore: 'L'elemento Initializer non è una costante in fase di compilazione'. –

+0

@GeorgeWS Si sta ricevendo quell'errore solo perché si sta tentando di inizializzarlo al risultato di una funzione (alloc e init sono funzioni). Se lo inizializzi a zero, e poi aggiungi if (obj == nil) e inizializzi lì, starai bene. – Rob

3

Se si dispone di molte proprietà di livello di classe, è possibile che un modello singleton sia in ordine. Qualcosa di simile a questo:

// Foo.h 
@interface Foo 

+ (Foo *)singleton; 

@property 1 ... 
@property 2 ... 
@property 3 ... 

@end 

E

// 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 

ora accedere le proprietà a livello di classe come questo:

[Foo singleton].property1 = value; 
value = [Foo singleton].property2; 
+4

Questa implementazione singleton non è thread-safe, non usarla – klefevre

+1

Ovviamente non è thread-safe, sei la prima persona a menzionare la sicurezza del thread e di default non ha senso il sovraccarico di sicurezza del thread in contesti non thread-safe cioè single filo. –

+0

Sarebbe abbastanza facile usare un 'dispatch_once' qui. –

52

Come si vede nella WWDC 2016/XCode 8 (what's new in LLVM session @ 5: 05). Le proprietà delle classi possono essere dichiarate come segue

@interface MyType : NSObject 
@property (class) NSString *someString; 
@end 

NSLog(@"format string %@", MyType.someString); 

notare che le proprietà di classe non sono mai sintetizzati

@implementation 
static NSString * _someString 
+ (NSString *)someString { return _someString; } 
+ (void)setSomeString:(NSString *)newString { _someString = newString; } 
@end 
+2

Dovrebbe forse essere esplicitato che questo è solo _ zucchero per le dichiarazioni di accesso. Come hai notato, la proprietà non è sintetizzata: una variabile ('static') deve essere ancora dichiarata e utilizzata, ei metodi implementati esplicitamente, proprio come erano in precedenza. Anche la sintassi dei punti ha funzionato in precedenza. In tutto, questo sembra un affare più grande di quello che realmente è. –

+2

Il grosso problema è che è possibile accedere ai singleton dal codice Swift senza usare(), e il suffisso del tipo viene rimosso per convenzione. Per esempio. XYZMyClass.shared (Swift 3) invece di XYZMyClass.sharedMyClass() – Ryan

+0

Questo non sembra thread-safe. Se questo potrebbe essere mutato da diversi thread nel tuo codice, farei in modo di gestire la potenziale condizione di competizione che questo creerebbe. – smileBot

8

Come di Xcode 8 Objective-C supporta ora proprietà di classe:

@interface MyClass : NSObject 
@property (class, nonatomic, assign, readonly) NSUUID* identifier; 
@end 

Dal proprietà di classe non sono mai sintetizzati, devi scrivere la tua implementazione.

@implementation MyClass 
static NSUUID*_identifier = nil; 

+ (NSUUID *)identifier { 
    if (_identifier == nil) { 
    _identifier = [[NSUUID alloc] init]; 
    } 
    return _identifier; 
} 
@end 

si accede alle proprietà della classe utilizzando la sintassi del punto normale sul nome della classe:

MyClass.identifier; 
-3

[Prova questa soluzione è semplice] È possibile creare una variabile statica in una classe Swift quindi chiamare da qualsiasi Classe Objective-C.

+0

OP non ha chiesto come creare una proprietà statica in Swift, questo non risolve il suo problema. –

Problemi correlati