In iOS where is the right place to store configuration values? - ios

Im my AppDelegate.h
I am just defined the constants:
#define XXDefaultFeedbackRecipent #"feedback#app.com"
#define XXDefaultFeedbackSubject #"Feedback"
What is the right place to define these type of settings? They are not user settings but they do have the possibility of changing from one release to the next.

There's no right place but you may either put it in a 'Constants' file (I usually create a class called constants, delete the interface and implementation of the class and keep the files for this purpose), or in the class where you use those defines.
A better way to keep this data, however, is to use the following:
// in your .h file
extern NSString * const XXDefaultFeedbackRecipent;
// in your .m file
NSString * const XXDefaultFeedbackRecipent = #"feedback#app.com";
p.s. there's a convention about writing #defines that wants you to write the names of your #defines in capital letters with words separated by underscore (e.g. MY_DEFINE). This is to prevent collisions with other stuff in C libraries and other files. Keep this in mind when writing your #defines.

You can keep them as constants in your class, and access them via extern in your .h file.
I would also recommend using consts, for type safety.
In your .h
extern NSString * const XXDefaultFeedbackRecipent;
extern NSString * const XXDefaultFeedbackSubject;
In your .m
NSString * const XXDefaultFeedbackRecipent = #"feedback#app.com";
NSString * const XXDefaultFeedbackSubject = #"Feedback";

I recommend the approach the other answers have explained. Using extern NSString * const
Avoid #defines for this sort of thing as everywhere you reference it, a new NSString will be allocated. Not a problem if your only referencing it once or twice but far from optimal.
Be careful not to mis-use this. For config values, service endpoints, etc. consider using a plist to store values. It makes editing config values much easier and allows for further flexibility with continuous integration setups, multiple service environments and remote config updates by push notification.

Related

Why do I need an implementation file (.m) when creating project-wide constants?

At the moment I create constants in this way:
// Constants.h
FOUNDATION_EXPORT NSString *const kTestConstant;
// Constants.m
NSString *const kTestConstant = #"TestConstant";
This of course works fine, however I'm puzzled on why I can't just have it all in the header file like this:
NSString *const kTestConstant = #"TestConstant";
If I do that, include Constants.h in various classes and use kTestConstant in those classes, I get redefinition errors at compile time. Why is that?
My theory is that by having a constant only on a header file, the file Constants.h is 'copy-pasted' into the class files that import it, consequently I end up with two copies of kTestConstant. However, by using an implementation file, that file is compiled and linked with the classes that import Constants.h. Is this more or less correct?
Essentially your analysis is correct except for the "modern" concept of "paste". The compilation unit is a concatenation of all header files directly or indirectly included/imported and the implementation file.
As always I recommend obtaining a good "C" language book and studying it, Objective-C is just a thin layer on top of "C". That is what I did years ago, still have the book.

Objective-C : #define vs extern const

I know this question has been asked before, but I can't seem to find information about it in Apple's documentation; maybe some of you guys did.
A lot of Objective-C code has cross-file constants in a .h file, using #define.
Others use the approach of a .m with constants and extern them in the .h file.
I understand the difference, both pros and cons, but does Apple state which one to use in iOS development?
The trouble with using #defines over an extern, is that the compiler doesn't get to do any type checking. If you #define a string, there is nothing to stop you using it where you actually want, say, a number. If you use a static NSString instead, the compiler will emit a warning if you try to use it somewhere where it isn't expecting a string.
Apple's recommendation is extern:
Define constants for strings used for such purposes as notification names and dictionary keys. By using string constants, you are ensuring that the compiler verifies the proper value is specified (that is, it performs spell checking).
Admittedly they are inconsistent about this sometimes.
A #define defines a macro which is replaced before compilation starts where as extern *** *const merely modifies a variable so that the compiler will flag an error if you try to change it. There are some cases in that you would use a #define because you can't use a extern *** *const. In theory a extern *** *const will take up memory and requires a reference to memory but this is insignificant as it maybe optimized away from the compiler.
extern *** *consts are a lot more compiler and debug friendlier then #defines this can be the deciding point when you decide which one to use.
Some see that pre-processor directives like #define are frowned upon which would suggest you should be using extern *** *const over #define
But whilst the pre-processor is frowned open some say it is more secure then a variable as it can't be changed at runtime whereas a variable can.
Both have there advantages and disadvantages and I don't think (I can't find anything myself) that Apple recommends one over the other. My personal opinion is to use a mix of them both using a pre-processor directive #define over a extern *** *const where it would seem more beneficial, this is what I do.
If you have some global constants, for example in a Constants.h which is imported in your prefix header and you're using a #define macro for these constants it's going to rebuild your whole project if you make any changes to these constants. In that case it is better to split your constants and use extern for strings, integers and everything else that you can use extern for.
For example if you have extern NSString *const kServerURL; and you change your server address it's not going to rebuild your whole project but if you use define there, it's going to rebuild it. So the only purpose at least for me is for optimising the compile time.

Storing constants of any type with values in objective c

I'm new to objective c and I come from .NET background. I want to create a static class which will store will constants of any type (NSString,NSArray etc.) In .NET I would create a class and declare the const using "public const". How do I do the same in objective C? I had a look at creating a class which is a Subclass of NSObject but I wasn't sure and I don't want to use #define .Any help would be appreciated
Sample:
public class ApplicationConstants()
{
public const string globalString="This is a global string";
public const int sample=1;
}
I want to do something like this in objective c. Any link to some sample code would be really helpful. I also want to store arrays in the same way
Objective-C doesn't have class variables. There are two ways to achieve the same functionality:
use global variables with a name that indicates what class they belong to. E.G.
Header:
extern NSString *const BCOpinionatedClassWillStartOpiningNotification;
Implementation:
NSString *const BCOpinionatedClassWillStartOpiningNotification = #"BCOpinionatedClassWillStartOpiningNotification";
2 Create a class method that returns the value. E.G:
Header:
#interface BCOpinionatedClass
+(NSInteger)theBestIntegerEver;
#end
Implementation:
#implementation OpinionatedClass
+(NSInteger)theBestIntegerEver
{
return 1;
}
#end
You should not create this object (you really shouldn't create this object in C# either, but we're discussing ObjC right now). There is no object-oriented sense to a class that is "all the constants for a program." The correct place to put these values is in the classes that require them. So for instance, if you create a string constant for an NSNotification name, you should put its definition in the class that posts that notification.
In general, you do not put these kinds of constants inside of classes at all. You use prefix naming for them to indicate what they relate to. So for instance, the UIApplicationDidBecomeActiveNotification string constant is defined in the UIApplication.hheader file, thus:
UIKIT_EXTERN NSString *const UIApplicationDidBecomeActiveNotification;
UIKIT_EXTERN is a portability macro that resolves to just extern. Inside of the .m, you would have some line like:
NSString *const UIApplicationDidBecomeActiveNotification = #"UIApplicationDidBecomeActiveNotification";
While this constant goes inside of UIApplication.h, it is not inside of the UIApplication class, or any class. Objective-C doesn't provide the kind of scoping you're used to in C#. We use naming prefixes instead of namespaces.
The same rules apply for other types; this isn't just for strings. For example, again from UIApplication.h:
typedef NS_ENUM(NSInteger, UIApplicationState) {
UIApplicationStateActive,
UIApplicationStateInactive,
UIApplicationStateBackground
} NS_ENUM_AVAILABLE_IOS(4_0);
Here we define an enum, which indirectly is defining various integer values. Again, this is just in the header file. There is no encapsulation inside of UIApplication. We only know that it's part of UIApplication because of its prefix.
Even those things that are ubiquitous through the whole system, such as UIKitDefines.h and Availability.h, are still broken out into their own contained headers. There is no "here are all the definitions for all UIKit objects" file. You shouldn't create one for your program either.
Note that this use of global variables is only appropriate for constants. You should not use globals this way for mutable variables. They should belong to some class and have accessors. But again, they would belong to the class that uses them, not a "generic program stuff" class.
See also #Benedict Cohen's answer for how to implement these things as class methods, which has some benefits (it permits subclassing, for instance). It is also somewhat less convenient, and is not the most common approach.
Take a look at this answer. For example, you can define string constants in your headers like:
FOUNDATION_EXPORT NSString *const aConstantString;
and then initialize them in the implementation file:
NSString *const aConstantString = #"Some constant string";
In case you're wondering what FOUNDATION_EXPORT is, in NSObjCRuntime.h it is #defined as extern.
Use singleton with an NSArray to hold your data.
The objects to add can be initialised and added to the NSArray on your singleton init and be ready for use.
Or even better, Use an NSMutableDictionary and you can store and retrieve objects using keys.
The singleton pattern:
Singleton with ARC
NSDictionary:
https://developer.apple.com/library/mac/documentation/cocoa/reference/foundation/classes/nsdictionary_class/Reference/Reference.html
I think you are having some confusion with changing coding domains.
In .NET,
public const string globalString="This is a global string";
defines a constant string that is immutable, which means, you cannot change the content of the memory location pointed by globalString. And you can define such variable in class level.
On the other hand, Objective-C being a successor of pure C, is not fully object oriented. Instead, it supports declaring immutable variables at module level. And that means, you can define a immutable variable in your header and that would be accessible from any module importing that header.
So you can declare your constant variable at module level like, at the top of your header like,
extern const NSString* const globalString;
And then you need to initialize it, at the top of your implementation(.m) file like
const NSString* const globalString = #"This is a global string";
Here, const NSstring* const denotes the variable globalString points to a unique memory location (the trailing const) and it contains some immutable value(#"This is a global string") that cannot be changed (the leading const). So it becomes the equivalent to your .NET declaration.
Another thing to remember here that NSString,NSArray,NSDictionary, etc. are immutable by nature (with NSMutableString, NSMutableArray, NSMutableDictionary, etc. as their mutable counterparts) and you dont need to specify the leading const keyword for them as that is defined implicitly. So it is ok to write:
extern NSString* const globalString;
For declaring a constant string.
Hope it helps to understand.

Clear Unused Entity Warnings For Static Int In xCode

I have a project, with a file that I call 'Keys.h'
In that file, I declare strings and integers that are used across the project, some of which are integers, some of which are strings.
All of the strings work fine; however, if I use integers, I get an unused variable warning.
For a string, (lfPrefs is a dictionary of user preferences)
static NSString * kUserLFPrefs = #"lfPrefs";
This works fine, and does not produce any errors.
For an integer, (I have integers to define the current mode because it seems a bit snappier than comparing strings all the time).
static int kModeLiveFeed = 1001;
static int kModeEventFeed = 2002;
These work just fine, except that they are showing an unused entity warning.
I'd prefer to use the integers over strings, mostly because I read that comparisons are much faster, takes up less memory, etc.
My question is how can I stop the warnings while still getting access to my integer keys?
(Or, should I just use strings)
I can suggest two different methods.
If you want to keep such variables in .h file, you may prefer using define if you will not be changing the value run time like;
#define kModeLiveFeed 1001
If you will be changing the variable value run time, I suggest keeping them in a .m file instead of in a .h file and creating only one instance of the .m file by using singleton. Then, even if you continue to get a warning from the .m file, you can disable it by the steps below:
Select your project from the left navigator to open project settings view.
Then, select your target.
Go to Build Phases tab and open compile resources area.
Click to the right side of your .m file to add a compiler flag as -w
I hope it helps.
You may be misunderstanding the meaning of static in C/Objective-C (this question should help). You should use const rather than static to define constants, and you should define the value of an integer/string constant in a .m file, with a corresponding declaration in the .h file. Or better yet, use an enum if you have a related set of integer constants.
Here is Apple's documentation on constants, which includes the above information as well as naming recommendations (e.g., PRConstant is preferred over the classic Mac OS-style kConstant).

objective-c globals key string?

I am accessing to a a object stored in NSUserDefaults by using a key string from several places in my project. To avoid a mistake when typing a key string i would like to set in global. Is it possible ??
[[NSUserDefaults standardUserDefaults] objectForKey:#"UD_GPS_LAST_UPDATE"];
There are different ways to do that. Two common methods is to use a global NSString constant or a preprocessor #define directive.
Global constant
A popular approach is to use a global variable. You need to add it to some file. It could be an existing file or a separate file. Make sure that it's outside the #implementation section if it exists. It could look something like this:
NSString *const MyStringConstantIdentifier = #"UD_GPS_LAST_UPDATE";
Then add the same identifier with the extern attribute to a header file which you include in all source files where you want to use the string constant.
extern NSString *const MyStringConstantIdentifier;
Now MyStringConstantIdentifier will refer to the same string in all places where it's used.
[[NSUserDefaults standardUserDefaults] objectForKey:MyStringConstantIdentifier];
Preprocessor directive
Another approach is to use a preprocessor #define directive in a header file. Make sure that you include the header file in all source files where you want to use the identifier.
#define MyStringConstantIdentifier #"UD_GPS_LAST_UPDATE"
Now when you include that header file MyStringConstantIdentifier will be available as a shortcut for writing #"UD_GPS_LAST_UPDATE". This will however put the burden on the preprocessor rahter than the compiler. The difference from using a global variable is that when you use
[[NSUserDefaults standardUserDefaults] objectForKey:MyStringConstantIdentifier];
the preprocessor will actually substitute MyStringConstantIdentifier with #"UD_GPS_LAST_UPDATE" so that the code that the compiler processes looks like this:
[[NSUserDefaults standardUserDefaults] objectForKey:#"UD_GPS_LAST_UPDATE"];
Where this can be a problem is if parts of your code ever moves into a library. Because preprocessing happens at (actually just before depending on how you look at it) compile time the substitution will replace the constant with the string at all places where it is used. Let's say that this is defined in a library. Whenever the string is changed in the library any application which uses it will have to be recompiled.
Yes it is possible.
Indeed this is the best way to use all the constant strings.
You can create a GlobalConstantsAndKeys.h file with below and others
#define kUDGpsLastUpdate #"UD_GPS_LAST_UPDATE"
and then use it throughout your project.
[[NSUserDefaults standardUserDefaults] objectForKey:kUDGpsLastUpdate];
Yes, create example.h file and write #define SEND_MESSAGE_ID #"2" or what ever u want then go to .pch file and import example.h to see it in all app.

Resources