2010-07-22 11 views
11

Utilizzo un set di file Constant.m, uno per target, per definire elementi specifici per ciascun target. Per esempio:Come posso utilizzare un NSArray come costante globale?

// Constants.h 
extern NSString * const kDatabaseFileName; 
//Constants.m 
NSString * const kDatabaseFileName = @"target_one.sqlite"; 

Vorrei anche per definire un NSArray per ciascuno dei miei obiettivi:

NSArray * const kLabelNames = [[NSArray alloc] initWithObjects: 
    @"nameLabel", @"addressLabel", nil]; 

Ma questo dà "l'errore: elemento inizializzatore non è costante". Anche l'uso di 'arrayWithObjects` non funziona. È perché le stringhe nel mio array non sono costanti?

Come posso impostare un array come costante globale? Grazie.

+0

possibile duplicato di [Come dichiaro un array come una costante in Objective-C?] (Http://stackoverflow.com/questions/2436463/how-do-i-declare-an-array- as-a-constant-in-objective-c) –

risposta

6

Se si desidera un insieme di costanti che includa i tipi NS, è consigliabile inserirli tutti in un singleton.

Si può avere un singolo file di intestazione e più file di implementazione (uno per target). Finché tutti implementano la classe dichiarata nel file di intestazione, si dovrebbe andare bene.

2

È necessario creare una classe che contenga le costanti nei metodi di classe. Quindi puoi aggiungere la classe a qualsiasi target e chiamare i metodi per ottenere le costanti in oggetti come gli array. Variare la classe o l'implementazione della classe per modificare il ritorno delle costanti.

Se lo si utilizza molto, è possibile creare un protocollo che definisce i nomi dei metodi. Quindi scambiare la classe che implementa il protocollo in ciascun target in modo che lo stesso codice restituisca valori diversi a seconda delle necessità.

28

In Objective-C, gli oggetti possono essere allocati solo in heap, quindi non c'è modo di creare un NSArray nella memoria statica. Tuttavia, è possibile creare una serie C di puntatori a costanti NSString in questo modo ...

NSString * const kLabelNames[] = { 
    @"Foo", @"Bar", @"Baz" 
}; 

... e quindi è possibile scrivere i metodi della classe come questo ...

+ (NSArray *)labelNames 
{ 
    static NSArray *names; 
    if (names == nil) { 
     names = [[NSArray alloc] initWithObjects:kLabelNames count:3]; 
    } 
    return names; 
} 

Edit

Si noti che con l'introduzione di nuove tecnologie come ARC, Grand Central Dispatch e la nuova sintassi letterale per gli array, ora c'è un modo più semplice per realizzare qualcosa di simile. Si noti che l'esempio di seguito fornisce anche una maggiore sicurezza del thread, sebbene l'esempio originale possa aver incorporato un blocco @synchronized o uno dei numerosi altri meccanismi, per ottenere risultati simili.

+ (NSArray *)labelNames 
{ 
    static NSArray *names; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     names = @[@"Foo", @"Bar", @"Baz"]; 
    }); 

    return names; 
} 

Tuttavia, l'esempio sopra riportato non risolve completamente la domanda originale. Se veramente è necessario un allineamento costante globale, l'esempio precedente potrebbe essere riscritto in modo analogo come la risposta originale, pur sfruttando GCD:

NSString * const kLabelNames[] = { 
    @"Foo", @"Bar", @"Baz" 
}; 

+ (NSArray *)labelNames 
{ 
    static NSArray *names; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     names = [NSArray arrayWithObjects:kLabelNames count:3]; 
    }); 

    return names; 
} 
+0

Nel caso in cui si voglia sostituire tale conteggio: 3 con un valore dinamico, è possibile utilizzare il buon vecchio modo C per ottenere le dimensioni dell'array. '' 'Conteggio: sizeof (kLabelNames)/sizeof (kLabelNames [0])' '' –

1

Se si vuole evitare di fare un controllo NULL su ogni utilizzo, è possibile creare una sottoclasse del metodo di inizializzazione di NSObject +. Questo verrà chiamato una volta, la prima volta che la tua classe viene istanziata (e ancora una volta per sottoclasse, se qualche sottoclasse viene istanziata), ed è un ottimo posto per fare questo tipo di inizializzazione.

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html%23//apple_ref/occ/clm/NSObject/initialize

+1

Se leggi attentamente il documento collegato, vedrai che 'initialize' può essere (e spesso lo è) chiamato più di una volta:" Il runtime invia 'initialize' a ogni classe in un programma esattamente una volta appena prima che la classe, * o qualsiasi classe che ne erediti *, invii il suo primo messaggio all'interno del programma." [enfasi aggiunta] – jlehr

+0

Ho appena visto il tuo commento e aggiornato la mia risposta. – StilesCrisis

5

Ecco un approccio molto più semplice:

Declare NSString con elementi separati da virgola (o quello che volete delimitatore)

NSString *const kLabelNames = @"Foo,Bar,Baz"; 

poi convertire in NSArray quando ne hai bisogno:

NSArray *namesArray = [kLabelNames componentsSeparatedByString:@","]; 
4

Utilizzare una macro:

#define SOME_ARRAY (@[@"blah", @"asdf", @"qwerty"]) 
Problemi correlati