2010-01-19 15 views
44

स्थिर स्ट्रिंग का उपयोग करना मैं एक छोटे से रूप में जब यह उपयोग करने के लिए सबसे अच्छा है करने के लिए उलझन में हूँ:जब बनाम #define

#define AppQuitGracefullyKey @"AppQuitGracefully" 

मैं सी के लिए इस तरह सवाल देखा है की

static NSString *AppQuitGracefullyKey = @"AppQuitGracefully"; 

बजाय या C++ और मुझे लगता है कि यहाँ क्या अलग है कि इस उद्देश्य सी के लिए विशेष रूप है, एक वस्तु का उपयोग, और iPhone की तरह एक डिवाइस पर,, वहाँ ढेर किया जा सकता है कोड स्थान या स्मृति मुद्दों है कि मैं अभी तक समझ में नहीं आता है।

एक उपयोग होगा:

appQuitGracefully = [[NSUserDefaults standardUserDefaults] integerForKey: AppQuitGracefullyKey]; 

या यह शैली का मामला है?

धन्यवाद।

उत्तर

58

आप एक स्थिर उपयोग करते हैं, संकलक अपनी बाइनरी में स्ट्रिंग के ठीक एक प्रतिलिपि एम्बेड कर देंगे और बस के आसपास है कि स्ट्रिंग के लिए संकेत दिए गए पास, अधिक कॉम्पैक्ट बाइनरी में जिसके परिणामस्वरूप। यदि आप #define का उपयोग करते हैं, तो प्रत्येक उपयोग पर स्रोत में संग्रहीत स्ट्रिंग की एक अलग प्रति होगी। निरंतर स्ट्रिंग कोलेसिंग dups के कई संभाल लेंगे, लेकिन आप बिना किसी कारण के संयोजक काम कठिन बना रहे हैं।

+9

निरंतर स्ट्रिंग कोलेसिंग लिंकर संकलक का काम है, नहीं है। – kennytm

+1

यह सही नहीं है। ऑब्जेक्टिव-सी का उपयोग करता है [स्ट्रिंग होना शामिल] (https://en.wikipedia.org/wiki/String_interning) के रूप में वर्णित [यहां] (http://nshipster.com/equality/)। 'define' _not_ प्रत्येक उपयोग के लिए स्ट्रिंग की एक प्रति स्टोर करता है। और @ केनेटीएम सही है, संकलक ऐसा करता है, लिंकर –

+1

@ एंड्रेफ्राटेलि नहीं, वास्तव में, निरंतर स्ट्रिंग कोलेसिंग एक लिंकर अनुकूलन है, और इसे सी और सीएफ/एनएसएसआरटीएस दोनों के लिए ओएस एक्स/मैकोज़ में स्थिर लिंकर द्वारा कार्यान्वित किया जाता है। । यह स्ट्रिंग होना शामिल का उपयोग नहीं किया जाता है, और यह संकलक द्वारा नहीं किया जाता है (हालांकि संकलक वस्तु अपने सृजन फाइल बाहर लिखने से पहले तार ही सम्मिलित हो सकते हैं)। आप कोड को देख सकते हैं जो [लिंकर स्रोत] में करता है (http://opensource.apple.com/source/ld64/ld64-264.3.102/)। तो नहीं, केनिटम सही नहीं है; यह वास्तव में लिंकर है। – alastair

3

मैं static का उपयोग जब मैं एक पुस्तकालय या एक रूपरेखा से NSString प्रतीकों का निर्यात करने की जरूरत है। मैं #define का उपयोग जब मैं कई स्थानों है कि मैं आसानी से बदल सकते हैं में एक स्ट्रिंग की जरूरत है। वैसे भी, संकलक और लिंकर अनुकूलन का ख्याल रखेगा।

14

"static const" vs "#define" vs "enum" देखें। static का मुख्य लाभ प्रकार सुरक्षा है।

इसके अलावा, #define दृष्टिकोण इनलाइन स्ट्रिंग कॉन्सटेनेशन की लचीलापन पेश करता है जो स्थैतिक चर के साथ नहीं किया जा सकता है, उदा।

#define ROOT_PATH @"/System/Library/Frameworks" 
[[NSBundle bundleWithPath:[email protected]"/UIKit.framework"] load]; 

लेकिन यह शायद एक अच्छी शैली नहीं है :)।

+33

मैं बहुत हैरान हूँ। मुझे नहीं पता था कि एक स्ट्रिंग "@" एक स्ट्रिंग "@" मान्य थी। –

+0

आपकी टिप्पणी से cdespinosa के उत्तर में, क्या इसका मतलब है कि #define का उपयोग डुप्लीकेटेशन नहीं करेगा? – user523234

+0

@ user523234 यह करता है। कंपाइलर [स्ट्रिंग इंटरनेशनल] का उपयोग करता है (https://en.wikipedia.org/wiki/String_interning) –

4

कुछ खोज (this प्रश्न/अन्य बातों के अलावा इस सवाल का जवाब) करने के बाद मुझे लगता है कि यह है कि कभी भी कहने के लिए जब आप उपयोग कर रहे हैं स्ट्रिंग शाब्दिक @"AppQuitGracefully" निरंतर स्ट्रिंग बनाई गई है, और कोई बात नहीं कितनी बार आप इसका इस्तेमाल यह इंगित करेगा महत्वपूर्ण है ही वस्तु के लिए।

तो मुझे लगता है (और मैं मुझे माफी माँगता हूँ अगर मैं गलत हूँ) के ऊपर जवाब में इस वाक्य गलत है: If you use a #define, there will be a separate copy of the string stored in the source on each use.

3

का उपयोग #define:

आप का मान डिबग नहीं कर सकते पहचानकर्ता

#define और अन्य मैक्रो के साथ काम पूर्व प्रोसेसर, आप का निर्माण/पहले भागो यह preprocess स्रोत कोड है, यह सभी मैक्रो के साथ काम करेंगे होगा (प्रतीक # से शुरू) मारा है,

का एक काम है

मान लीजिए, आपके द्वारा बनाए गए,

#define LanguageTypeEnglish @"en" 

और अपने कोड में 2 स्थानों पर इस का इस्तेमाल किया।

NSString *language = LanguageTypeEnglish; 
NSString *languageCode = LanguageTypeEnglish; 

यह सब स्थानों पर, "LanguageTypeEnglish" @"en" साथ की जगह लेगा। तो @"en" की 2 प्रतियां उत्पन्न की जाएंगी। यानी

NSString *language = @"en"; 
NSString *languageCode = @"en"; 

याद रखें, इस प्रक्रिया तक, संकलक चित्र में नहीं है।

सभी मैक्रो preprocessing के बाद, संकलक चित्र में आता है, और इसे इस तरह इनपुट कोड मिलेगा,

NSString *language = @"en"; 
NSString *languageCode = @"en"; 

और यह संकलन।

स्थिर उपयोग:

यह गुंजाइश सम्मान करता है और टाइप-सुरक्षित है। आप संकलन की प्रक्रिया के दौरान पहचानकर्ता

का मूल्य अगर संकलक पाया डीबग कर सकते हैं,

static NSString *LanguageTypeRussian = @"ru"; 
तो

यह जांच करेगा कि एक ही नाम के साथ चर पहले से संग्रहीत, यदि हाँ, तो वह केवल सूचक पारित करेंगे उस चर के, यदि नहीं, तो वह उस चर को बनाएगा और इसके पॉइंटर को पास करेगा, अगली बार इसके बाद यह केवल इसके सूचक को ही पास करेगा।

इसलिए स्थैतिक का उपयोग करके, चर के भीतर केवल एक प्रति चर उत्पन्न होती है।

4

मैं वास्तव में न तो अनुशंसा करता हूं, आपको इसके बजाय extern का उपयोग करना चाहिए।

FOUNDATION_EXPORT NSString * const AppQuitGracefullyKey; 

मीटर

NSString * const AppQuitGracefullyKey = @"AppQuitGracefully"; 

मैं आमतौर पर इन डाल: ऑब्जेक्टिव-सी पहले से ही FOUNDATION_EXPORT जो extern से more portable है, इसलिए एक वैश्विक NSString उदाहरण यह कुछ ऐसा दिखाई देगा को परिभाषित करता है घोषणा फाइलें (जैसे MyProjectDecl.h) और जब चाहें आयात करें।

इन तरीकों के लिए कुछ मतभेद हैं:

  • #define इस प्रकार सुरक्षित नहीं होने के रूप में कई कमियां, है। यह सच है कि इसके लिए कामकाज हैं (जैसे) लेकिन क्या बात है? और इसके अलावा, उस दृष्टिकोण के लिए डिबगिंग नुकसान हैं। कंपाइलर्स स्थिरांक पसंद करते हैं। this चर्चा देखें।
  • स्थिर वैश्विक visible in the file they are declared.
  • निर्वासन सभी फाइलों को चर से दिखाई दे रही हैं। यह स्थिर के साथ विरोधाभास है।

स्थिरता और बाहरी दृश्यता में भिन्नता है।यह भी उल्लेखनीय है कि इन तरीकों का न स्ट्रिंग (यहां तक ​​कि नहीं #define) डुप्लिकेट के रूप में संकलक String Interning का उपयोग करता है को रोकने के लिए है।

NSString *a = @"Hello"; 
NSString *b = @"Hello"; 
BOOL wtf = (a == b); // YES 

ऑपरेटर == रिटर्न YES केवल तभी दो चर एक ही कहने पर बात: this NSHipster post में वे सबूत दिखाते हैं। और जैसा कि आप देख सकते हैं, यह करता है।

निष्कर्ष है: वैश्विक स्थिरांक के लिए FOUNDATION_EXPORT का उपयोग करें। यह डीबग दोस्ताना है और आपकी परियोजना के दौरान दिखाई देगा।

संबंधित मुद्दे