IOS एप्लिकेशन में वैश्विक स्थिरांक कहाँ संग्रहीत करें?


111

मेरे iOS ऐप के अधिकांश मॉडल एक वेब सर्वर को क्वेरी करते हैं। मैं सर्वर के आधार URL को संचयित करना चाहता हूँ। यह कुछ इस तरह दिखेगा:

// production
// static NSString* const baseUrl = "http://website.com/"

// testing
static NSString* const baseUrl = "http://192.168.0.123/"

एक पंक्ति या दूसरी टिप्पणी करके, मैं तुरंत अपने सर्वर को इंगित करने वाले सर्वर को बदल सकता हूं। मेरा सवाल है, आईओएस में वैश्विक स्थिरांक भंडारण के लिए सबसे अच्छा अभ्यास क्या है? एंड्रॉइड प्रोग्रामिंग में, हमारे पास यह अंतर्निहित स्ट्रिंग्स संसाधन फ़ाइल है । किसी भी गतिविधि में (एक UIViewController के बराबर ), हम उन स्ट्रिंग स्थिरांक को पुनः प्राप्त कर सकते हैं:

String string = this.getString(R.string.someConstant);

मैं सोच रहा था कि क्या आईओएस एसडीके में स्थिरांक स्टोर करने के लिए एक अनुरूप जगह है। यदि नहीं, तो ऐसा करने के लिए Objective-C में सबसे अच्छा अभ्यास क्या है?

जवाबों:


145

आप भी कर सकते हैं

#define kBaseURL @"http://192.168.0.123/"

"स्थिरांक" शीर्षक फ़ाइल में, कहते हैं constants.h। फिर करो

#include "constants.h"

हर फ़ाइल के शीर्ष पर जहाँ आपको इस स्थिरांक की आवश्यकता होती है।

इस तरह, आप संकलक झंडे के आधार पर सर्वरों के बीच स्विच कर सकते हैं, जैसे कि:

#ifdef DEBUG
    #define kBaseURL @"http://192.168.0.123/"
#else
    #define kBaseURL @"http://myproductionserver.com/"
#endif

मैं "constants.h"दृष्टिकोण का उपयोग करता हूं , जिसके staticआधार पर चर घोषित करता हूं #ifdef VIEW_CONSTANTS ... #endif। इसलिए मेरे पास एक एप्लिकेशन-वाइड कॉन्स्टेंट फ़ाइल है, लेकिन मेरी प्रत्येक अन्य कोड फ़ाइलों #defineमें #includeकॉन्स्टेंट फाइल को शामिल करने से पहले कॉन्स्टेंट के अलग-अलग सेट शामिल हैं (उन सभी को परिभाषित करता है जो "संकलक चेतावनी का उपयोग नहीं करते हैं")।

2
वहाँ दो मुद्दों मैं इस समाधान के साथ भाग गया है। सबसे पहले, जब मैंने उपयोग किया #decalare, तो मुझे एक अवैध त्रुटि मिली, जिसमें कहा गया था कि " अवैध प्रीप्रोसेसिंग डाइरेक्टिव डिक्लेयर "। इसलिए मैंने इसे #defineबदले। दूसरी समस्या स्थिरांक का उपयोग कर रही है। मैं एक और स्थिरांक बनाना चाहता था static NSString* const fullUrl = [NSString stringWithFormat:@"%@%@", kbaseUrl, @"script.php"], लेकिन जाहिर है कि एक अभिव्यक्ति के साथ कॉस्ट बनाना गैरकानूनी है। मुझे त्रुटि मिलती है " आरंभीकरण तत्व स्थिर नहीं है "।
जोजो

1
@ साइरिल एंड्रॉइड वास्तव में अभ्यास करने के लिए दिलचस्प है, कुछ संभावनाएं हैं जो आप आईओएस पर कल्पना नहीं कर सकते थे! वैसे भी उत्तर के लिए धन्यवाद
klefevre

8
जहां संभव हो #Dfine पर कॉन्स्ट प्रेफर करें - आपको बेहतर कंपाइल-टाइम चेकिंग मिलती है, और डीबगिंग बेहतर काम करती है।
occulus

2
@AnsonYao आमतौर पर जब मेरे साथ ऐसा होता है तो मैं #define से एक अर्धविराम निकालना भूल जाता हूं, जैसे #define kBaseURL @"http://192.168.0.123/";
Gyfis

168

ठीक है, आप चाहते हैं कि घोषणा से संबंधित इंटरफेस के लिए स्थानीय - ऐप-वाइड कॉन्स्टेंट फ़ाइल अच्छी बात नहीं है।

साथ ही, इसका extern NSString* constउपयोग करने के बजाय केवल एक प्रतीक घोषित करना बेहतर है #define:


SomeFile.h

extern NSString* const MONAppsBaseUrl;

SomeFile.m

#import "SomeFile.h"

#ifdef DEBUG
NSString* const MONAppsBaseUrl = @"http://192.168.0.123/";
#else
NSString* const MONAppsBaseUrl = @"http://website.com/";
#endif

C ++ की संगत एक्सटर्नल डिक्लेरेशन की चूक के अलावा, यह वही है जो आप आमतौर पर Apple के ओब्ज-सी फ्रेमवर्क में उपयोग करते हुए देखेंगे।

यदि निरंतर को केवल एक फ़ाइल या फ़ंक्शन के लिए दिखाई देने की आवश्यकता है, तो static NSString* const baseUrl आपके *.mलिए अच्छा है।


26
यह निश्चित नहीं है कि स्वीकृत उत्तर में #define की वकालत करने के लिए 40 वोट क्यों हैं - कॉन्स्ट वास्तव में बेहतर है।
अक्टूबर को

1
निश्चित रूप से कॉन्स्टेंस NSString #define से बेहतर है, यह स्वीकृत उत्तर होना चाहिए। #define हर बार एक नया स्ट्रिंग बनाता है जो परिभाषित मूल्य का उपयोग किया जाता है।
jbat100

1
@ jbat100 मुझे नहीं लगता कि यह एक नया तार बनाता है। मुझे लगता है कि कंपाइलर पता लगाता है कि क्या आपका कोड एक ही स्टैटिक स्ट्रिंग 300,000 बार बनाता है और केवल एक बार ही इसे बनाएगा। @"foo"जैसा है वैसा नहीं है [[NSString alloc] initWithCString:"foo"]
अभि बेकर्ट

@AbhiBeckert मुझे लगता है कि बिंदु jbat बनाने की कोशिश कर रहा था कि जब #defineइसका इस्तेमाल किया जाता है (यानी सूचक समानता विफल हो सकती है) अपने डुप्लिकेट के डुप्लिकेट के साथ समाप्त करना संभव है - ऐसा नहीं है कि एनएसएसट्रिंग शाब्दिक अभिव्यक्ति जब भी निष्पादित होती है एक अस्थायी पैदा करता है।
जस्टिन

1
मैं सहमत हूं कि #define एक बुरा विचार है, मैं सिर्फ उस त्रुटि को सुधारना चाहता था जो उसने बनाई थी कि यह कई वस्तुओं का निर्माण करेगी। इसके अलावा, संकेत समानता भी स्थिरांक के लिए पर भरोसा नहीं किया जा सकता है। इसे NSUserDefaults या किसी चीज़ से लोड किया जा सकता है। हमेशा उपयोग करें
अभि बेकर्ट

39

वैश्विक स्थिरांक को परिभाषित करने का तरीका:


AppConstants.h

extern NSString* const kAppBaseURL;

AppConstants.m

#import "AppConstants.h"

#ifdef DEBUG
NSString* const kAppBaseURL = @"http://192.168.0.123/";
#else
NSString* const kAppBaseURL = @"http://website.com/";
#endif

फिर आपके {$ APP} में- -Pfix.pch फ़ाइल:

#ifdef __OBJC__
  #import <UIKit/UIKit.h>
  #import <Foundation/Foundation.h>
  #import "AppConstants.h"
#endif

यदि आप किसी समस्या का अनुभव करते हैं, तो पहले सुनिश्चित करें कि आपके पास Precompile उपसर्ग हैडर विकल्प NO पर सेट है।


5

आप स्ट्रिंग स्थिरांक को भी इस तरह से परिवर्तित कर सकते हैं:

  #define kBaseURL @"http://myServer.com"
  #define kFullURL kBaseURL @"/api/request"

4

मुझे लगता है कि ऐसा करने का एक और तरीका कहीं अधिक सरल है और आप इसे केवल उन फ़ाइलों में शामिल करेंगे जिनकी आपको उन्हें शामिल करने की आवश्यकता है, सभी फ़ाइलों की तरह नहीं। pch उपसर्ग फ़ाइल के साथ:

#ifndef Constants_h
#define Constants_h

//Some constants
static int const ZERO = 0;
static int const ONE = 1;
static int const TWO = 2;

#endif /* Constants_h */

उसके बाद आप इस हेडर फाइल को हेडर फाइल में शामिल करते हैं जो आप चाहते हैं। आप इसे उस विशिष्ट वर्ग के लिए हेडर फ़ाइल में शामिल करते हैं जिसे आप इसमें शामिल करना चाहते हैं:

#include "Constants.h"

मेरे परीक्षण में, डिबगर (Xcode's lldb) में स्थैतिक स्थिरांक प्रयोग करने योग्य नहीं हैं। "error: use of undeclared identifier .."
jk7

3
  1. मैं YourPROJECT-Prefix.pch फ़ाइल में वैश्विक स्थिरांक को परिभाषित करता हूं।
  2. #define BASEURl @"http://myWebService.appspot.com/xyz/xx"
  3. BASEURL का उपयोग करने के लिए प्रोजेक्ट में कहीं भी:

    NSString *LOGIN_URL= [BASEURl stringByAppendingString:@"/users/login"];

अपडेट किया गया: Xcode 6 में आपको अपने प्रोजेक्ट में बनाई गई डिफ़ॉल्ट .pch फ़ाइल नहीं मिलेगी। तो कृपया Xcode 6 में PCH फ़ाइल का उपयोग करें अपने प्रोजेक्ट में .pch फ़ाइल डालने के लिए करें।

अपडेट: स्विफ्ट के लिए

  1. नई स्विफ्ट फ़ाइल बनाएं [वर्ग के बिना खाली] कहें [AppGlobalMemebers]
  2. और सदस्य को सही / परिभाषित घोषित करना

    उदाहरण:

    var STATUS_BAR_GREEN : UIColor  = UIColor(red: 106/255.0, green: 161/255.0, blue: 7/255.0, alpha: 1)  //
    1. यदि आप किसी भी वर्ग फ़ाइल में ऐप के वैश्विक सदस्य को परिभाषित करना चाहते हैं, तो कहो कि अपीलीय या एकल वर्ग या किसी भी वर्ग की परिभाषा से ऊपर के सदस्य की घोषणा करें

2

वैश्विक घोषणाएं दिलचस्प हैं लेकिन, मेरे लिए, कोड के लिए मेरे तरीके में गहराई से परिवर्तन होने से कक्षाओं के वैश्विक उदाहरण हैं। यह मुझे कुछ दिनों के लिए समझ में आ गया कि वास्तव में इसके साथ कैसे काम करना है इसलिए मैंने जल्दी से इसे यहाँ संक्षेप में प्रस्तुत किया

मैं कोर डेटा एक्सेस, या कुछ ट्रेड लॉगिक्स को फिर से इकट्ठा करने के लिए, कक्षाओं के वैश्विक उदाहरणों (1 या 2 प्रति प्रोजेक्ट, यदि आवश्यक हो) का उपयोग करता हूं।

उदाहरण के लिए यदि आप एक केंद्रीय वस्तु को सभी रेस्तरां तालिकाओं को संभालना चाहते हैं जो आप स्टार्टअप में वस्तु बनाते हैं और वह यह है। यदि आपको इसे सहेजने की आवश्यकता नहीं है, तो यह ऑब्जेक्ट डेटाबेस एक्सेस को संभाल सकता है या इसे मेमोरी में संभाल सकता है। यह केंद्रीकृत है, आप केवल उपयोगी इंटरफेस दिखाते हैं ...!

यह एक महान मदद, वस्तु उन्मुख और एक ही जगह पर आप सभी सामान प्राप्त करने का एक अच्छा तरीका है

कोड की कुछ पंक्तियाँ:

@interface RestaurantManager : NSObject
    +(id) sharedInstance;
    -(void)registerForTable:(NSNumber *)tableId;
@end 

और ऑब्जेक्ट कार्यान्वयन:

@implementation RestaurantManager

+ (id) sharedInstance {
    static dispatch_once_t onceQueue;

    dispatch_once(&onceQueue, ^{
        sharedInstance = [[self alloc] init];
        NSLog(@"*** Shared instance initialisation ***");
    });
    return sharedInstance;
}

-(void)registerForTable:(NSNumber *)tableId {
}
@end

इसका उपयोग करने के लिए यह वास्तव में सरल है:

[[RestaurantManager साझा किया गया] पंजीकरण] पंजीकरण योग्य: [एनएसएनम्बर नंबरडाइट: 10]]


3
इस डिज़ाइन पैटर्न का तकनीकी नाम सिंगलटन है। en.wikipedia.org/wiki/Singleton_pattern
बेसिल बॉर्क

साझाकरण में स्थैतिक डेटा (स्टेटिक क्लास नहीं) रखना एक अच्छा विचार नहीं है।
Onder OZCAN

1

स्वीकृत उत्तर में 2 कमजोरियां हैं। सबसे पहले, जैसा कि दूसरों ने बताया कि इसका उपयोग #defineडिबग करने के लिए कठिन है, इसके बजाय extern NSString* const kBaseUrlसंरचना का उपयोग करें । दूसरा, यह स्थिरांक के लिए एक एकल फ़ाइल को परिभाषित करता है। IMO, यह गलत है क्योंकि अधिकांश वर्गों को उन स्थिरांक तक पहुंचने की आवश्यकता नहीं है या उन सभी को एक्सेस करने के लिए प्लस फाइल को फूला हुआ बनाया जा सकता है यदि सभी स्थिरांक वहां घोषित किए जाते हैं। एक बेहतर समाधान 3 अलग-अलग परतों में स्थिरांक को संशोधित करना होगा:

  1. सिस्टम परत: SystemConstants.hया AppConstants.h जो वैश्विक दायरे में स्थिरांक का वर्णन करता है, जिसे सिस्टम में किसी भी वर्ग द्वारा पहुँचा जा सकता है। यहाँ केवल उन स्थिरांक की घोषणा करें जिन्हें विभिन्न वर्गों से एक्सेस किया जाना चाहिए जो संबंधित नहीं हैं।

  2. मॉड्यूल / उप-प्रणाली परत:, ModuleNameConstants.hएक स्थिरांक / उप-प्रणाली के अंदर, संबंधित वर्गों के सेट के लिए विशिष्ट हैं, जो स्थिरांक का एक सेट का वर्णन करता है।

  3. कक्षा की परत: कांस्टेंट कक्षा में रहते हैं और केवल इसके द्वारा उपयोग किए जाते हैं।

केवल 1,2 प्रश्न से संबंधित हैं।


0

एक दृष्टिकोण जो मैंने पहले प्रयोग किया है वह एक फ़ाइल बनाने Settings.plistऔर NSUserDefaultsलॉन्च का उपयोग करके इसे लोड करने के लिए है registerDefaults:। फिर आप निम्नलिखित के साथ इसकी सामग्री तक पहुँच सकते हैं:

// Assuming you've defined some constant kMySettingKey.
[[NSUserDefaults standardUserDefaults] objectForKey:kMySettingKey];

जब मैंने कोई Android विकास नहीं किया है, तो ऐसा लगता है कि यह आपके द्वारा वर्णित स्ट्रिंग्स संसाधन फ़ाइल के अनुरूप है। केवल नकारात्मक पक्ष यह है कि आप सेटिंग्स (जैसे DEBUGमोड में) के बीच स्वैप करने के लिए प्रीप्रोसेसर का उपयोग नहीं कर सकते हैं । मुझे लगता है कि आप एक अलग फ़ाइल में लोड कर सकते हैं, हालांकि।

NSUserDefaults प्रलेखन।


9
जब आप चाहते हैं कि एक बिट overkill नहीं है एक स्थिर है? और यह भी, क्यों यह एक संभावित परिवर्तनीय फ़ाइल में डाल दिया? (खासकर जब यह आपके मास्टर सर्वर के आईपी के रूप में महत्वपूर्ण है, जिसके बिना आपका ऐप काम नहीं करता है)।
साइरिल

मुझे लगता है कि इस दृष्टिकोण के कई लाभ हैं, सबसे महत्वपूर्ण यह है कि आपकी सेटिंग्स सही प्रारूप ( NSStringऔर NSNumber, आदि) में वापस आ जाती हैं । ज़रूर, आप अपने #defineएस को एक ही काम करने के लिए लपेट सकते हैं , लेकिन फिर उन्हें संपादित करना उतना आसान नहीं है। plistसंपादन इंटरफ़ेस अच्छा है, भी है। :) जबकि मैं सहमत हूं कि आपको एन्क्रिप्शन कुंजी जैसे सुपर सीक्रेट सामान को वहां नहीं रखना चाहिए, मैं उन उपयोगकर्ताओं के बारे में बहुत चिंतित नहीं हूं जो उन जगहों पर आस-पास हैं जो उन्हें नहीं होना चाहिए - यदि वे ऐप को तोड़ते हैं, तो यह उनकी खुद की गलती है ।
क्रिस डोले

1
यकीन है, मैं आपके तर्कों से सहमत हूं। जैसा कि आप कहते हैं, मैं अपने #defineएस को सही प्रकार से वापस करने के लिए लपेटता हूं , लेकिन मैं इस तरह की कॉन्स्टेंट फ़ाइलों को संपादित करने का आदी हूं, जैसा कि मैंने हमेशा इस तरह के ग्लोबल कॉन्स्टेंट को एक अलग कॉन्स्टेंट फाइल में रखना सीखा है, जिन दिनों से मैंने पास्कल सीखा था। पुराने 286 पर :) और जैसा कि उस उपयोगकर्ता के लिए है जो हर जगह के आसपास है, मैं भी सहमत हूं, यह उनकी गलती है। यह सिर्फ स्वाद की बात है, वास्तव में।
साइरिल

@ क्रिस डोबल: नहीं, एंड्रॉइड में संसाधन फाइलें NSUserDefaults के लिए समान नहीं हैं। SharedPreferences और प्राथमिकताएँ NSUserDefaults (NSUserDefaults की तुलना में अधिक शक्तिशाली) के बराबर Android हैं। एंड्रॉइड में संसाधनों को सामग्री से अलग करने के लिए तर्क दिया जाता है, जैसा कि स्थानीयकरण के लिए, और कई अन्य उपयोगों के लिए।
mrd

0

एक संख्या के लिए आप इसका उपयोग कर सकते हैं

#define MAX_HEIGHT 12.5

0

मैं एक कॉन्फ़िगरेशन ऑब्जेक्ट का उपयोग करता हूं जो एक से आरंभ करता हैplist । अप्रासंगिक बाहरी सामान के साथ अन्य वर्गों को क्यों परेशान करें?

मैंने eppz!settignsइसी वजह से मिट्टी बनाई । NSUserDefaults से डिफ़ॉल्ट मानों को शामिल करने के लिए सहेजने के लिए उन्नत उन्नत लेख देखें plist

यहां छवि विवरण दर्ज करें


सच। Wordpress किसी भी तरह से हल नहीं करता है: ... / ... इस सीधे लिंक पर जाएं वैसे भी blog.eppz.eu/?p=926 : D
Geri Borbás
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.