Where to Store Global Constants in an iOS Application

Where to store global constants in an iOS application?

You could also do a

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

in a "constants" header file, say constants.h. Then do

#include "constants.h"

at the top of every file where you need this constant.

This way, you can switch between servers depending on compiler flags, as in:

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

Global constants in an iOS application

I prefer something similar to solution 3:

Create a Constant file, which you include in the Prefix.pch.

Though I really hate the #define approach.

Instead, in Constants.h use:

extern NSString* const kStringConstant;

and define it in Constants.m:

NSString* const kStringConstant = @"SomeStringConstant"

This answer explains why you shouldn't use #define.

Global constants file in Swift


Structs as namespace

IMO the best way to deal with that type of constants is to create a Struct.

struct Constants {
static let someNotification = "TEST"
}

Then, for example, call it like this in your code:

print(Constants.someNotification)

Nesting

If you want a better organization I advise you to use segmented sub structs

struct K {
struct NotificationKey {
static let Welcome = "kWelcomeNotif"
}

struct Path {
static let Documents = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
static let Tmp = NSTemporaryDirectory()
}
}

Then you can just use for instance K.Path.Tmp

Real world example

This is just a technical solution, the actual implementation in my code looks more like:

struct GraphicColors {

static let grayDark = UIColor(0.2)
static let grayUltraDark = UIColor(0.1)

static let brown = UIColor(rgb: 126, 99, 89)
// etc.
}

and


enum Env: String {
case debug
case testFlight
case appStore
}

struct App {
struct Folders {
static let documents: NSString = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
static let temporary: NSString = NSTemporaryDirectory() as NSString
}
static let version: String = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String
static let build: String = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as! String

// This is private because the use of 'appConfiguration' is preferred.
private static let isTestFlight = Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt"

// This can be used to add debug statements.
static var isDebug: Bool {
#if DEBUG
return true
#else
return false
#endif
}

static var env: Env {
if isDebug {
return .debug
} else if isTestFlight {
return .testFlight
} else {
return .appStore
}
}
}

Where's the best place to store constants in an iOS app?

I agree with Alex Coplan's answer with an important addition.

Put all your constants in a file named "Constants.h" (or w/e you want)

EDIT:

  • When I answered this question three years ago, I was on the #define bandwagon, check below for a revision.

Constants.h

#define kFilterDate @"date"
#define kFilterRadius @"radius"
#define kFilterSort @"sort"

//Global Strings
#define kDividingString @" / "

//Strings
#define kTour @"Tour"
#define kToursKey @"tours"

But instead of importing it in any file you need it, import it in your prefix file so that all of your headers import it automatically throughout your project.

Project_Prefix.pch

//
// Prefix header for all source files of the project
//

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

REVISION

All though all the previous information will still work, there are some things we can do to be a little bit more safe about our constants.

Create your constants in your Constants.h file using const variables

//Filters
FOUNDATION_EXPORT NSString *const kFilterDate;
FOUNDATION_EXPORT NSString *const kFilterRadius;
FOUNDATION_EXPORT NSString *const kFilterSort;

//Global Strings
FOUNDATION_EXPORT NSString *const kDividingString;

//Strings
FOUNDATION_EXPORT NSString *const kTour;
FOUNDATION_EXPORT NSString *const kToursKey;

And in Constants.m

//Filters
NSString *const kFilterDate = @"date";
NSString *const kFilterRadius = @"radius";
NSString *const kFilterSort = @"sort";

//Global Strings
NSString *const kDividingString = @" / ";

//Strings
NSString *const kTour = @"Tour";
NSString *const kToursKey = @"tours";

This can still be imported into your prefix file like above, but only use constants that are truly global in the file to do that. Ones that are used frequently in many places. Dumping all your constants into this file will cause your code that uses any constant to be coupled to the constants file. Thus, if you try to reuse the code, the constants file has to come with it. This isn't always necessarily bad, and many times is intended (which is fine), but limiting dependencies is always a good idea.

A few things about the revision:

  • FOUNDATION_EXPORT vs extern. The first one compiles different for C and C++. It basically means extern, but in C++ will add the "C" flag.
  • consts vs defines. consts are type safe and respect scope. defines are the exact opposite.

Where should constant data be stored for an app?

There's a difference.

If you want to store constants, then use NSUserDefaults.

If you just want them to be there, in your code, just lying there then, #define should be fine.

Store global strings in iOS in Swift for app-wide use

This is what exactly I wanted: Sharing strings and variables throughout ios app

I am able to share strings such as apikeys, tokens by using NSUserDefaults

saving:

NSUserDefaults.standardUserDefaults().setObject("apistringhere", forKey: "apikey")
NSUserDefaults.standardUserDefaults().synchronize()

getting:

NSUserDefaults.standardUserDefaults().objectForKey("apikey")

Storing Global/Environment Variables in iOS Swift Apps

What I always do is probably a more flexible approach than checking constants in your code and littering different values of the same variable per environment everywhere.

It is not necessary to create .xcconfig files either.

Setting up the whole thing is a little more work but you will see that it is very easy to use afterwards.

In my example you see how I set different REST endpoints for production/UITest/development builds in my Toeppersee iOS app.

Changes to your Info.plist

First, just define a new constant and select a name that identifies your content, in my case it is TS_WEBSERVICE_URL:
Info.plist
Make sure to set its value to the name you chose, enclosed in $() (brackets, not braces!), in my case it's $(TS_WEBSERVICE_URL).

Build settings

In your build settings tab, add custom "user defined" build parameters, again with the same name:

build settings

You see that you can define values for Debug, UITests and Release. And that I use this mechanism for a whole lot of things that are different in the environments.

Adding more environments

If you need more environments, add them on your master project node's Info tab (like I probably did here with UITests):
Add environments

Use the values in code

Now for the easy part: use your newly defined values in your code. It all boils down to getting an NSBundle instance and reading the value defined in your Info.plist which has been substituted automatically during build process.

Objective C:

NSString *webserviceURL = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"TS_WEBSERVICE_URL"];

Swift:

let webserviceURL = Bundle.main.object(forInfoDictionaryKey: "TS_WEBSERVICE_URL") as! String

Just one line of code per environment setting.

One thing I have not shown, but which is also fairly easy: just define a category to NSBundle and supply new methods called webserviceUrl and similar methods. They can then be called like this: Bundle.main.webserviceUrl() which even more simplifies the source code.

Edit: write extension to Bundle object (optional)

To achieve the aforementioned simplified access to the webservice URL, a new Swift file is created and called (for example): Bundle+AppAdditions.swift

import Foundation

// An extension (or category in Objective C) extends any types functionality,
// in our case the NSBundle foundation class.
extension Bundle {
// get the webservice URL from an NSBundle instance
public func webserviceUrl() -> String {
// get an object for info dictionary key and cast it as string
return self.object(forInfoDictionaryKey: "TS_WEBSERVICE_URL") as! String
}
}

The extension works directly on any given Bundle instance, not necessarily only the main bundle. Example:

let url = Bundle.main.webserviceUrl()

or any other bundle, e.g. for an App Clip Extension containing an InitialViewController:

let url = Bundle(for: InitialViewController.self).webserviceUrl()

I would actually add another static extension method to get the app clip extension bundle. But that's optional as well ;-)

Is it good practice to use global variables and constants? (Swift 5)

You can use a static variable of a struct to do this more elegant:

struct Repository {
static var googleUser: String?
}

and access/set googleUser using the struct type:

Repository.googleUser = user

Or even better, use a singleton class like this:

class Repository {
static let shared = Repository()
var googleUser: String?
}

then you can use it directly:

Repository.shared.googleUser = user

or inject the singleton instance to whichever class want to use googleUser.

where to store global objects in iOS

You can make global objects accessible by placing them in a class with class methods for accessing global objects, implementing +(void)load to prepare these objects, and storing them in static variables.

Header:

@interface GlobalObjects
+(void)load;
+(MyObject1*)myObject1;
@end

Implementation:

#import "GlobalObjects.h"
static MyObject1* _myObject1 = nil;
@implementation GlobalObjects
+(void)load {
_myObject1 = [[MyObject1 alloc] init];
}
+(MyObject1*)myObject1 {
return myObject1;
}
@end

Usage:

MyObject1 *shared = [GlobalObjects myObject1];

You could also make the variable static inside its method for lazy initialization.



Related Topics



Leave a reply



Submit