2009-06-29 8 views
16

में निरंतर परिभाषित करना मैं उद्देश्य-निरंतर निरंतर परिभाषित करना चाहता हूं।उद्देश्य-सी

पहले मैं निम्नलिखित समारोह था:

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

मैं एक निरंतर "Documents_Dir" केवल एक बार परिभाषित करना चाहते हैं - समारोह कहा जाता हो जाता है जब और उसके बाद पूर्व में बने मूल्य तक पहुँचने के लिए।

मैं निम्नलिखित कोड है, जो काम नहीं किया की कोशिश की है:

#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 \ 
} \ 

मैं precompiler निर्देशों के साथ मजबूत नहीं कर रहा हूँ, इसलिए किसी भी मदद की सराहना की जाएगी।

उत्तर

34

प्रस्तावना: यह प्रीकंपलर निर्देशों और सच्चे स्थिरांक के बीच अंतर को समझने का भुगतान करता है। संकलक कोड बनाता है इससे पहले #define बस टेक्स्ट प्रतिस्थापन करता है। यह संख्यात्मक स्थिरांक और typedefs के लिए बहुत अच्छा काम करता है, लेकिन यह हमेशा कार्य या विधि कॉल के लिए सबसे अच्छा विचार नहीं है। मैं इस धारणा के तहत काम कर रहा हूं कि आप वास्तव में एक सच्चे निरंतर चाहते हैं, जिसका अर्थ है कि खोज पथ बनाने के लिए कोड केवल एक बार निष्पादित किया जाना चाहिए।


अपने MyClass.m फ़ाइल में चर को परिभाषित करने और इसलिए की तरह एक +initialize विधि में पॉप्युलेट:

static NSArray *documentsDir; 

@implementation MyClass 

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

... 

@end 

static संशोधक केवल संकलन के भीतर से दिखाई दे रही यूनिट जहां इसे घोषित किया जाता है। एक साधारण निरंतर के लिए, यह सब आपको चाहिए।

वर्ग उपवर्गों है, तो +initialize एक बार प्रत्येक उपवर्ग (डिफ़ॉल्ट रूप से) के लिए है, तो आप चाहे documentsDirnil इसे करने के लिए आवंटित करने से पहले है जांचना चाहेंगे, तो आप स्मृति रिसाव नहीं है बुलाया जाएगा। (या, जैसा कि पीटर लुईस बताते हैं, आप जांच सकते हैं कि वर्तमान में कक्षा शुरू की जा रही है या नहीं, == या -isMemberOfClass: विधि का उपयोग कर माइक्लास है।) यदि उप-वर्गों को भी निरंतर सीधे पहुंचने की आवश्यकता है, तो आपको पूर्व-घोषित करने की आवश्यकता होगी में MyClass.h फ़ाइल extern के रूप में चर (जो बच्चे कक्षाओं में शामिल हैं):

extern NSArray *documentsDir; 

@interface MyClass : NSObject 
... 
@end 

आप निर्वासन के रूप में चर पूर्व घोषित हैं, तो आप static कीवर्ड परिभाषा से निकालना होगा संकलन से बचने के लिए त्रुटियों। यह आवश्यक है इसलिए चर कई संकलन इकाइयों का विस्तार कर सकते हैं। (आह, सी की खुशियों ...)

नोट: ऑब्जेक्टिव-सी कोड में, extern के रूप में कुछ घोषणा करने के लिए बेहतर तरीके से उपयोग करने के लिए है OBJC_EXPORT (एक #define<objc/objc-api.h> में घोषित), जो आधारित सेट किया गया है चाहे आप सी ++ का उपयोग कर रहे हों या नहीं। extern को OBJC_EXPORT के साथ बस बदलें और आप कर चुके हैं।


संपादित करें: मैं सिर्फ एक related SO question पर हुआ।

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

"स्थिर" संकलक कि documentsDir प्रभावी रूप से एक वैश्विक चर रहा है बताता है, हालांकि केवल:

+0

धन्यवाद, लेकिन जब मैं अपने प्रोजेक्ट का निर्माण, मैं निम्नलिखित चेतावनी मिलती है: 'searchPath' में परिभाषित किया गया लेकिन उनका उपयोग नहीं। चेतावनी उन सभी फ़ाइलों को छोड़कर दिखाई देती है जहां इसे सीधे उपयोग किया जाता है। निरंतर परिभाषित फ़ाइल को सटीक हेडर में शामिल किया गया है। क्या इस चेतावनी से छुटकारा पाने का कोई तरीका है? धन्यवाद। –

+0

ऐसा इसलिए है क्योंकि वे एकाधिक फाइलों में प्रतीक आयात किए जा रहे हैं। चूंकि प्रश्न में फ़ाइल को कई अन्य फाइलों में शामिल किया जा रहा है, उप-वर्गों के बारे में मेरे मार्गदर्शन का उपयोग करें - चर को हेडर में बाहरी के रूप में घोषित करें, फिर इसे केवल एक स्थान (एक .m फ़ाइल में) चुनें, इसे स्थिर के रूप में घोषित करें, और एक (संभवतः अलग) इसे शुरू करने के लिए जगह। यदि आप पहले से ही ऐसा कर रहे हैं और त्रुटि बनी रहती है, तो अप्रयुक्त प्रतीकों के बारे में चेतावनियों को दबाने के लिए कंपाइलर को बताने के लिए __attribute __ ((अप्रयुक्त)) के साथ परिवर्तनीय घोषणा उपसर्ग करें। (मैं व्यक्तिगत रूप से #Ufine UNUSED __attribute __ ((अप्रयुक्त)) का उपयोग करता हूं, इसके लिए शॉर्टेंड के रूप में।) –

+0

ध्यान दें कि यदि MyClass उप-वर्गीकृत है, तो प्रारंभिकता को कई बार कहा जाएगा, इसलिए यदि आप प्रारंभिक उपयोग करने जा रहे हैं, तो आपको इसका उपयोग करने की आवश्यकता होगी: अगर (स्वयं == [MyClass वर्ग]) { searchPath == ...; } –

12

सबसे आसान समाधान सिर्फ रास्तों को बदलने के लिए एक स्थिर चर होने के लिए और केवल एक बार यह evalutate, इस तरह करने के लिए है समारोह के भीतर सुलभ। तो इसे शून्य करने के लिए शुरू किया गया है, और दस्तावेज़ प्राप्त करने के लिए पहली कॉल इसे निष्क्रिय कर देगी और फिर आगे की कॉल पूर्व-निकासी गई मान वापस कर देगी।

+0

+1 अच्छा कॉल, मैं भूल गया था कि आप एक फ़ंक्शन या विधि के अंदर एक स्थिर चर घोषित कर सकते हैं! यह वास्तव में सबसे आसान तरीका है, लेकिन ध्यान रखें कि कोई अन्य संकलन इकाई (सबक्लास या अन्यथा) प्रतीक का संदर्भ देने में सक्षम नहीं होगी। यदि आपको केवल एक फ़ाइल में निरंतर आवश्यकता है, तो इस दृष्टिकोण को आजमाएं। –

+1

बस मुझे इसे तुरंत चालू किए बिना संख्याओं की एक कभी-कभी बदलती सरणी उपलब्ध कराने के लिए आवश्यक नहीं था। यदि आप अपने वर्ग विधियों में दस्तावेजों का उपयोग करना चाहते हैं, तो "स्थिर एनएसएसटींग * दस्तावेज डीआईआर = शून्य;" कक्षा विधि के बाहर हालांकि। –

1

छोटे पीटर एन लुईस कोड के बारे में अनुकूलन:

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

क्या यह वास्तव में एक अनुकूलन है? मेरा मतलब है, क्या यह किसी भी तरह से तेज़ है? (ऐसा लगता है कि यह मेरे जैसा ही होगा।) क्या आप वाकई कम वर्ण नहीं हैं? यदि उत्तरार्द्ध, मैं पठनीयता के प्रिंसिपल पर इस विधि से असहमत हूं। यह अनावश्यक रूप से भ्रमित है, आईएमओ। – livingtech

+0

तेज़ नहीं, लेकिन सुरक्षित: मैंने "ऑब्जेक्टएट इंडेक्स: 0" को "lastObject" के साथ बदल दिया। –