objective-c globals key string? - ios

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.

Related

NSUserDefaults in iOS9 and XCode 7 does not return values

I'm using NSUserDefaults to retrieve values. Like for example a user name.
I have created a constants.h file added it my viewcontroller like this
#import "constants.h"
In the constants.h - Username is defined as
#define USERNAME #"Monty Python"
then in my viewDidLoad, I try and read the value like this
NSString *userName = [[NSUserDefaults standardUserDefaults] stringForKey:USERNAME];
But userName is allway nil/null - so are my other keys.
How does NSUserDefaults know to use my Constants.h file? Is my code looking in the correct 'location'? Why are my values always nil - both in the debugger and NSLog?
thx
How does NSUserDefaults know to use my Constants.h file?
It doesn't. There is no connection whatever between the two, and any expectation that there would be one is just wrong. Your Constants.h file configures some global variables in code, available to your other code as globals (provided that code imports that file). NSUserDefaults is a way of saving and retrieving a .plist file of key-value pairs on disk. They are totally different things, for totally different purposes.
In your code, you are using the Constants.h file as a way of supplying your code with the names of the keys to be used in NSUserDefaults. That is good practice! But this has nothing to do with how the values corresponding to those keys are going to get into NSUserDefaults in the first place.
The way to set "default defaults" (that is, initial values for each key-value pair to be kept in NSUserDefaults) — if that is what you're trying to do — is through code that runs very early and calls registerDefaults:.
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
Saving:
[currentDefaults setObject:#"Jon" forKey:#"myName"];
Getting:
[currentDefaults objectForKey:#"myName"]

Any smarter way to define constants in bulk?

I want to have macros for all constant strings in the project, which I am assigned to maintain.
The format of database fields are like #"first_name", #"last_name", etc.
What I want is like follows:
#define kFirstName #"first_name"
#define kLastName #"last_name" // And so on.
Problem: I have over 3500 unique fields with constant strings. I want each one of them to be defined as macro.
Any smarter way to do this. I am thinking of manually copy, paste & edit each one of them.
Tagging as iOS & Objective-C, as the project itself is an iPad Application.
In general, defining constants like this is the way to go on iOS, so you're on the right track.
You surely won't get around typing out each of the fields at least once.
I would recommend either of two approaches:
use multiple .h-files for the definition of all the constants. you can group the header files according to the definitions that they contain (e.g. all fields related to user data in UserDefinitions.h). that way you at least make sure that you don't have to import all the constants everywhere in your code. working with prefixes will also be helpful in this situation, so prefix all the Macros names with the .h-file that they contain, e.g. kUserFirstName so that you you know at first sight where this constant comes from
define all your constants in one (or multiple) property lists. that makes them easy to maintain. only make sure that you don't load the property file each time you use one of the constants, but rather cache the file once its loaded for the first time.
When using Core Data consider using mogenerator which creates constant values for you that you can reference for all of the attribute and relationship names.
the cleanest way is to make a pair of constants files (header and main). Create a new class (inheriting from whatever, NSObject say) call it constants. Delete the #interface and #implementation, so you have an empty header (except for #import Foundation/Foundation.h) and empty main (except for importing the header.)
then declare each in the header like this
extern NSString *const kFirstName;
and implement each (in the .m file) just like this
NSString *const kFirstName = #"Johnny";
make sure the .m file is added to your target, import the header where need be.

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.

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

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.

Resources