2009-06-29 16 views
16

Hedefte bir sabit tanımlamak istiyorum c. Objektifte bir sabit tanımlaması-

önce aşağıdaki işlevi vardı: Sadece bir kez sabit bir "Documents_Dir" tanımlamak istiyorum

+(NSString *) getDocumentsDir { 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES); 
    NSString *documentsDir = [paths objectAtIndex: 0]; 
    paths = nil; 
    return documentsDir; 
} 

- İşlevin çağrıldığı aldığında ve bundan sonra daha önce oluşturulmuş bir değere erişmek için.

ben işe yaramadı Aşağıdaki kodu, denedim:

#define getDocumentsDir \ 
{ \ 
#ifdef Documents_Dir \ 
return Documents_Dir; \ 
#else \ 
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES); \ 
NSString *documentsDir = [paths objectAtIndex: 0]; \ 
#define Documents_Dir [paths objectAtIndex: 0]; \ 
paths = nil; \ 
return Documents_Dir; \ 
#endif \ 
} \ 

Ben precompiler direktifleri güçlü değilim, bu yüzden herhangi bir yardım takdir edilecektir.

cevap

34

Prelude: Precompiler yönergeleri ve gerçek sabitler arasındaki farkı anlamak için öder. Bir #define sadece derleyici kodu oluşturmadan önce bir metin değişimi yapar. Bu, sayısal sabitler ve yazım hataları için harika çalışır, ancak işlev veya yöntem çağrıları için her zaman en iyi fikir değildir. Gerçekten doğru bir sabit olmasını istediğiniz varsayımı altında çalışıyorum, yani arama yolunu oluşturan kodun yalnızca bir kez çalıştırılması gerekir. senin MyClass.m dosyasında


, değişken tanımlamak ve bu yüzden böyle bir +initialize yönteminde bunu doldurmak:

static NSArray *documentsDir; 

@implementation MyClass 

+ (void) initialize { 
    if (documentsDir == nil) { 
     documentsDir = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES) lastObject] retain]; 
    } 
} 

... 

@end 

static değiştirici sadece derleme içinde görünür kılan beyan edildiği birim. Basit bir sabit için, ihtiyacınız olan her şey bu.

sınıf alt sınıflarını varsa, documentsDir kendisine atamadan önce nil olup olmadığını kontrol etmek isteyeceksiniz böylece bellek sızıntısı kalmamak, +initialize, (varsayılan olarak), her alt sınıf için bir kere çağrılır. (Veya Peter Lewis'in işaret ettiği gibi, şu anda başlatılmış olan sınıfın, veya -isMemberOfClass: yöntemini kullanarak MyClass olduğunu kontrol edebilirsiniz.) Alt sınıflar da doğrudan sabite erişmeye ihtiyaç duyarsa, önceden bildirmeniz gerekir. (çocuk sınıfları dahil) MyClass.h dosyada extern gibi değişken: Eğer extern olarak değişken önceden bildirirseniz

extern NSArray *documentsDir; 

@interface MyClass : NSObject 
... 
@end 

, sen derleme önlemek için tanımından static anahtar kelime kaldırmalısınız hatalar. Bu gereklidir, böylece değişken çoklu derleme birimlerini kapsayabilir. (Ah, C sevinçleri ...)

Not: Objective-C kodunda, extern olarak bir şey bildirmek için iyi bir yol kullanmaktır OBJC_EXPORT (a #define<objc/objc-api.h> ilan) set dayandığı C++ kullanıp kullanmadığınızı belirtin. extern'u OBJC_EXPORT ile değiştirin ve işiniz bitti.


Düzenleme: Sadece related SO question üzerine oldu.Sadece rağmen,

+(NSString *) getDocumentsDir { 
    static NSString *documentsDir = nil; 
    if (!documentsDir) { 
     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES); 
     documentsDir = [paths objectAtIndex: 0]; 
    } 
    return documentsDir; 
} 

"statik" documentsDir etkin bir küresel değişkendir derleyici söyler:

+0

Teşekkürler ama benim proje oluştururken, aşağıdaki uyarıyı alıyorum: 'searchpath' tanımlı ama kullanılmaz. Uyarı, doğrudan kullanıldığı yerlerde hariç tüm dosyalarda görünür. Tanımlanmış bir sabitin bulunduğu dosya precolmpiled başlıklarına dahil edilir. Bu uyarıdan kurtulmanın bir yolu var mı? Teşekkürler. –

+0

Bunun nedeni, sembolün birden çok dosyaya içe aktarılmalarıdır. Söz konusu dosya birçok dosyaya dahil edildiğinden, alt sınıflar hakkındaki rehberimi kullanın - değişkeni üstbilgide extern olarak ilan edin, sonra statik olarak bildirmek için yalnızca bir yer (.m dosyasında) seçin ve (muhtemelen farklı) yerleştirmek için yer. Şimdiden bunu yapıyorsanız ve hata devam ederse, derleyiciye kullanılmayan sembollerle ilgili uyarıları bastırması için __attribute __ ((kullanılmamış)) ile değişken bildirimini önekleyin. (Kişisel olarak #define UNUSED __attribute __ ((kullanılmamış)) bunun için kısayol olarak kullanıyorum.) –

+0

Not: Eğer MyClass alt sınıflanmış ise, başlatma birden çok kez çağrılacak, eğer başlatılacaksa, kullanmanız gerekecek: if (self == [Sınıfım sınıf]) { searchPath == ...; } –

12

kolay çözüm sadece statik bir değişken olmaya yollarını değiştirip bu gibi sadece bir kez değerlendirebilme olduğunu işlev içinde erişilebilir. Bu nedenle, sıfırlanacak ve ilk defa getDocumentsDir çağrısı bunu değerlendirecek ve daha sonraki çağrılar değerlendirilen değeri döndürecektir. Peter N Lewis koduyla ilgili

+0

+1 İyi bir çağrı, bir fonksiyon veya metot içinde bir statik değişken bildirebileceğinizi unutmuştum! Bu gerçekten de en kolay yoldur, fakat başka bir derleme biriminin (alt sınıf veya başka bir şekilde) sembolü referans gösteremeyeceğini unutmayın. Tek bir dosyada sabite ihtiyacınız varsa, bu yaklaşımı deneyin. –

+1

Sadece neyi tekrar tekrar oluşturmadan sürekli değişen bir sayı dizisi sunmak için ihtiyacım vardı. DocumentsDir'i sınıf yöntemlerinde kullanmak isterseniz, "statik NSString * documentsDir = nil;" sınıf yöntemi dışında olsa da. –

1

Küçük optimizasyonu:

-(NSString *) documentsDir { 
    static NSString *documentsDir = nil; 
    return documentsDir ?: (documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]); 
} 
+0

Bu aslında bir optimizasyon mu? Yani, bu bir şekilde daha hızlı mı? (Aynen bana benzeyecek gibi görünüyor.) Sadece daha az karakter olmadığından emin misiniz? Eğer ikincisiyse, okunabilirlik ilkesi konusunda bu yönteme katılmıyorum. Bu gereksiz kafa karıştırıcı IMO. – livingtech

+0

Daha hızlı değil, daha güvenli: "lastObject" ile "objectAtIndex: 0" değiştirdim. –

İlgili konular