37

I'm developing an app just now that fetches resources from a JSON API.

all of the resources have the same base URL:

http://api.mysite.com/resources.json
http://api.mysite.com/other_resources.json

I want to store the http://api.mysite.com/ string so it's available to all of my Controllers and Models, removing some duplication when writing the resource URLs.

Where's the best place to do this? The -prefix.pch file?

Any advice appreciated

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
bodacious
  • 6,608
  • 9
  • 45
  • 74

5 Answers5

65

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.
ColdLogic
  • 7,206
  • 1
  • 28
  • 46
  • I hate using `.h .m` for global constants. Having to write each variable name TWICE is a PAIN! – Hlung Jul 24 '15 at 10:40
  • 3
    Having clean, consistent, readable code is worth 10 times as much as twice your pain. – ColdLogic Jul 24 '15 at 19:24
  • For following case what should I do ? i am error "initialize element is not compile time constant for USER_LIST_URL" NSString *const SERVER_URL = @"http://www.google.com"; NSString *const USER_LIST_URL = [NSString stringWithFormat:@"%@/xml/index.cfm",SERVER_URL]; – Abbas Mulani Apr 29 '16 at 12:27
48

Personally I prefer using actual const variables rather than defines.

In a MyConstants.m file I have:

NSString *const kXYMySiteBaseURL = @"http://api.mysite.com/";
NSString *const kXYSomeOtherURL = @"http://www.google.com/";

where XY is my initials or some other "unique" prefix to avoid collisions with other constants.

Then I have a MyConstants.h file like this:

extern NSString *const kXYMySitBaseURL;
extern NSString *const kXYSomeOtherURL;

Depending on how many files need to access these constants, I might include it in the precompiled header like ColdFusion suggests in his answer.

This is how Apple defines their constants in most of the Core frameworks.

UIAdam
  • 5,303
  • 1
  • 27
  • 23
  • 2
    I know it's probably a negligible difference - but what are the implications on memory of defining a constant once (that lives for the duration of your app) VS defining instance/local variable using macros that are used and then GC'd on the fly? – bodacious Feb 12 '12 at 19:17
  • as you can read here https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingIvarsAndTypes.html, Apple encourages you not to use #define macros. Thats why i prefer this answer than the previous one – voghDev Jul 26 '14 at 14:18
  • It's a bit of memory savings. There is also the advantage the things like isEqual: or isEqualToString won't even bother comparing the strings because they are the same pointer. – gnasher729 Mar 03 '15 at 18:46
12

I just create a file called Globals.h with something like the following:

#define kBaseURL @"http://api.mysite.com/"

Then to use:

#import "Globals.h" // at the top

NSString *url = [NSString stringWithFormat:@"%@resources.json",kBaseURL];
Alex Coplan
  • 13,211
  • 19
  • 77
  • 138
4

I would create a singleton or use the AppDelegate and put the constants there.

Oscar Gomez
  • 18,436
  • 13
  • 85
  • 118
  • I would think very very carefully before creating a singleton - they make unit testing very difficult and it's normally possible to achieve the same thing without one. Using the app delegate is a better solution, but still not ideal. Many would consider it bad design to place too much responsibility on the app delegate. I would personally opt for creating a global header file which contains only constants as per Alex Coplan's answer. – Will Pragnell Feb 12 '12 at 17:24
  • @WillPragnell How does the header file make unit testing any easier than a Singleton? In general Singletons make unit testing difficult, but this seems like exactly the place where a Singleton shines. – Jackson Dec 28 '13 at 23:04
4

Yes, a global header would be an ideal solution. I wouldn't go as far as a singleton pattern unless plan on using it for other things like managing your data store. A singleton for globals is somewhat overkill.

Half_Duplex
  • 5,102
  • 5
  • 42
  • 58