How to properly define constants [duplicate] - objective-c

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Constants in Objective C
I'm designing a controller and I'm gonna need some constants inside it (locally, just for that controller). Looking at some sample code provided by Apple, I can see these lines:
#import "Constants.h"
#define kTextFieldWidth 260.0
static NSString *kSectionTitleKey = #"sectionTitleKey";
static NSString *kSourceKey = #"sourceKey";
static NSString *kViewKey = #"viewKey";
const NSInteger kViewTag = 1;
Can anyone explain to me what the difference between them is? Which style should I use? Are they dependent on the type of object/value you assign to them? Meaning use: static NSString * for strings, #define for floats and NSInteger for integers? How do you make the choice?

The #define keyword is a compile time directive that causes the define'd value to be directly injected into your code. It is global across the entire program and all linked libraries. So you can strike that off the list, based on your desire to create a constant for the controller only.
The main difference between static and const is that static variables can be changed after initialization, const ones cannot. If you want to be able to modify your variable after initialization then you should use the static keyword.
Hope that helps.

As Scott and benzado pointed out that is the best way to define your constant values. However as far as defines go it is harder to debug using defines as you can usually not easily see the expanded value in a debugger. You will only need to add an extern declaration to the header file of your class if your intentions are to expose the variable globally. And the next thing to remember is to put the const declaration after the pointer (*) or else you will get warnings of discard qualifiers from pointer in most uses.

Related

Can I access an ObjC constant by string name at runtime? [duplicate]

This question already has an answer here:
How do I lookup a string constant at runtime in Objective-C?
(1 answer)
Closed 7 years ago.
I know that Objective-C allows me to refer to selectors by name using #selector(#"name") How can I access the following constant by name at runtime? In other words, I would pass #"CONST_KEY" somewhere and get #"key" back.
const NSString* CONST_KEY = #"key";
I think I can do this by first creating a key-value dictionary and then querying it at runtime, but I'm not sure if there's a better implementation.
To clarify with a specific use case:
I want to use a collection view cell reuse identifier #"CONST_KEY", declared in my storyboard, and to be able to use this identifier to look up the value of CONST_KEY at runtime.
This way I hope to have a single place within my code to modify constants, rather than having to re-assign values in multiple classes. Having the two values linked will allow me to have a single action for all those cells using the CONST_KEY to define the action they are going to do.
Objective C is just a C with added object functionality. So "CONST_KEY" constant name is discarded during compilation. So you have to create your own class or use an NSDictionary to provide "constant_name"->"constant_value" functionality.
You don't need to call a selector to get the constant, you just need to expose it to your other classes. Also the constant should live inside of its relevant class. The method I use is the following.
in the header file right below your import statements (before #interface) declare this:
extern NSString *const CONST_KEY;
In the implementation file in the same place (above #interface and #implementation) declare this:
NSString *const CONST_KEY = #"key";
After you do that, in any class that imports the class where you declared your constant, you will be able to reference it simply with CONST_KEY
E.G.
[someDictionary objectForKey: CONST_KEY];
or
NSLog(#"%#", CONST_KEY);
etc etc – Using this convention is great for type safety. I use it all the time.

What does extern mean in an obj-c header [duplicate]

This question already has answers here:
What does the extern keyword mean?
(3 answers)
Closed 8 years ago.
what does this code mean?
// myheader.h
extern const NSUInteger Something;
#interface MyObject : NSObject
...
#end
What does extern mean here, and how can/will it be used? is it part of the object? is it global in the project? Does it matter where (in which header) is it defined? Is that a good practice?
This is plain C.
What does extern mean here, and how can/will it be used?
extern const NSUInteger Something;
It means:
There is a var with the name Something.
It has the type NSUInteger.
It cannot be changed (const)
Do not create that var, but link to a creation somewhere else in a file contained in the executable (extern).
Let's have an example:
Exporter.h
extern const NSUInteger Something;
Exporter.m (Or Exporter.c, since it is plain C.)
#import "Exporter.h"
const NSUInteger Something = 5; // This is the definition for the declaration above.
After defining that var in Exporter.m and extern declaring it in Exporter.h everyone that imports the Header can use it:
Importer.h or Importer.m (Or Importer.c, since it is plain C.)
#import "Exporter.h" (Or #include, since it is plain C.)
// Now the compiler knows that
// there is a global readonly var called Something,
// its type is int, and
// it is readonly.
Every importer will share one var. Without the extern keyword, there would be different vars.
Is it part of the object?
No. To be precise: An ivar is declared, if it is inside { … }that belongs to an #interface … or to an #implementation …. Whether this is done in a header or in an .m file is without any meaning.
Is it global in the project
It is global in your executable. (You call that "project" what is not precise, but okay.)
Does it matter where (in which header) is it defined?
No. That never matters in C. (The compiler sees the text after resolving imports and includes. It has no idea from where it came.) But in one translation unit (".m") you have to have a definition as shown above in Exporter.m.
Is that a good practice?
The problem with extern var declaration is that everyone importing Exporter.h can read and – that's important – change that var without any notification to other parts of your software dealing with Exporter.h (and Something). So it is nearly impossible to control the data flow.
In nowadays extern global vars are only used for const vars, as in your Q. That vars cannot be changed. So there is no problem and it is commonly accepted practice.

Difference between static const and #define in Objective-C [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
“static const” vs “#define” in C
In Objective-C what is the difference between the following two lines:
#define myInteger 5
static const NSInteger myInteger = 5;
Assume they're in MyClass.m above the implementation directive.
#define myInteger 5
is a preprocessor macro. The preprocessor will replace every occurrence of myInteger with 5 before the compiler is started. It's not a variable, it's just sort of an automatic find-and-replace mechanism.
static const NSInteger myInteger = 5;
This is a "real" variable that is constant (can't be changed after declaration). Static means that it will be a shared variable across multiple calls to that block.
When using #define the identifier gets replaced by the specified value by the compiler, before the code is turned into binary. This means that the compiler makes the substitution when you compile the application.
When you use const and the application runs, memory is allocated for the constant and the value gets replaced when the applicaton is ran.
Please refer this link:- Difference between static const and #define
There are differences:
Define is textual substitution:
Define is preprocessor textual substitution made before compilation. You will achieve the same effect when you textually replace 5 in every occurrence of define.
Static const is a variable in memory
Static const however is an instance of NSInteger type that resides in program memory. You cannot change it during runtime, but it is a value which is present in the memory and its own address as a variable.
#define myInteger 5 is a macro that declares a constant.
So wherever you use myInteger macro it gets replaced with 5 by the preprocessor engine.
const NSInteger myInteger = 5; declares a variable myInteger that holds the value 5.
But their usage is the same, that is they are constants that can be used to prevent hard coding.

When to use static string vs. #define

I am a little confused as to when it's best to use:
static NSString *AppQuitGracefullyKey = #"AppQuitGracefully";
instead of
#define AppQuitGracefullyKey #"AppQuitGracefully"
I've seen questions like this for C or C++, and I think what's different here is that this is specifically for Objective C, utilizing an object, and on a device like the iPhone, there may be stack, code space or memory issues that I don't yet grasp.
One usage would be:
appQuitGracefully = [[NSUserDefaults standardUserDefaults] integerForKey: AppQuitGracefullyKey];
Or it is just a matter of style?
Thanks.
If you use a static, the compiler will embed exactly one copy of the string in your binary and just pass pointers to that string around, resulting in more compact binaries. If you use a #define, there will be a separate copy of the string stored in the source on each use. Constant string coalescing will handle many of the dups but you're making the linker work harder for no reason.
See "static const" vs "#define" vs "enum". The main advantage of static is type safety.
Other than that, the #define approach introduces a flexibility of inline string concatenation which cannot be done with static variables, e.g.
#define ROOT_PATH #"/System/Library/Frameworks"
[[NSBundle bundleWithPath:ROOT_PATH#"/UIKit.framework"] load];
but this is probably not a good style :).
I actually would recommend neither, you should use extern instead. Objective-c already defines FOUNDATION_EXPORT which is more portable than extern, so a global NSString instance would look something like this:
.h
FOUNDATION_EXPORT NSString * const AppQuitGracefullyKey;
.m
NSString * const AppQuitGracefullyKey = #"AppQuitGracefully";
I usually put these in declaration files (such as MyProjectDecl.h) and import whenever I need.
There are a few differences to these approaches:
#define has several downsides, such as not being type safe. It is true that there are workarounds for that (such as #define ((int)1)) but what's the point? And besides, there are debugging disadvantages to that approach. Compilers prefer constants. See this discussion.
static globals are visible in the file they are declared.
extern makes the variable visible to all files. That contrasts with static.
Static and extern differ in visibility. It's also notable that neither of these approaches duplicates the string (not even #define) as the compiler uses String Interning to prevent that. In this NSHipster post they show proof:
NSString *a = #"Hello";
NSString *b = #"Hello";
BOOL wtf = (a == b); // YES
The operator == returns YES only if the two variables point at the same instance. And as you can see, it does.
The conclusion is: use FOUNDATION_EXPORT for global constants. It's debug friendly and will be visible allover your project.
After doing some search (this question/answer among other things) I think it is important to say that anytime when you are using string literal #"AppQuitGracefully" constant string is created, and no matter how many times you use it it will point to the same object.
So I think (and I apologize me if I'm wrong) that this sentence in above answer is wrong: If you use a #define, there will be a separate copy of the string stored in the source on each use.
I use static when I need to export NSString symbols from a library or a framework. I use #define when I need a string in many places that I can change easily. Anyway, the compiler and the linker will take care of optimizations.
USING #define :
you can't debug the value of identifier
work with #define and other macros is a job of Pre-Processor,
When you hit Build/Run first it will preprocess the source code, it will work with all the macros(starting with symbol #),
Suppose, you have created,
#define LanguageTypeEnglish #"en"
and used this at 2 places in your code.
NSString *language = LanguageTypeEnglish;
NSString *languageCode = LanguageTypeEnglish;
it will replace "LanguageTypeEnglish" with #"en", at all places.
So 2 copies of #"en" will be generated.
i.e
NSString *language = #"en";
NSString *languageCode = #"en";
Remember, till this process, compiler is not in picture.
After preprocessing all the macros, complier comes in picture, and it will get input code like this,
NSString *language = #"en";
NSString *languageCode = #"en";
and compile it.
USING static :
it respects scope and is type-safe.
you can debug the value of identifier
During compilation process if compiler found,
static NSString *LanguageTypeRussian = #"ru";
then it will check if the variable with the same name stored previously,
if yes, it will only pass the pointer of that variable,
if no, it will create that variable and pass it's pointer, next time onwards it will only pass the pointer of the same.
So using static, only one copy of variable is generated within the scope.

Global Variables in Cocoa/Objective-C?

According to Cocoa Programming for Mac OS X, 3rd Edition, on page 202 (chapter 13):
You will be registering, reading, and
setting defaults in several classes in
your application. To make sure that
you always use the same name, you
should declare those strings in a
single file and then simply #import
that file into any file in which you
use the names. There are several ways
to do this. For example, you could use
the C preprocessor’s #define command,
but most Cocoa programmers use global
variables for this purpose.
Is this really the correct best practice? Global variables? That seems insane to me – counter to everything I’ve ever been taught.
Would a better design be a simple Singleton class with these defined? Or is it really the correct best practice to go global? Is there a better pattern than either, given that many people consider Singletons to be globals in a pretty dress?
Just to be clear, the recommendation is to create immutable global variables instead of in-line string constants (hard to refactor and no compile-time checking) or #defines (no compile-time checking). Here's how you might do so...
in MyConstants.h:
extern NSString * const MyStringConstant;
in MyConstants.m:
NSString * const MyStringConstant = #"MyString";
then in any other .m file:
#import "MyConstants.h"
...
[someObject someMethodTakingAString:MyStringConstant];
...
This way, you gain compile-time checking that you haven't mis-spelled a string constant, you can check for pointer equality rather than string equality[1] in comparing your constants, and debugging is easier, since the constants have a run-time string value.
[1] In this use, you are essentially using the pointer values as the constants. It just so happens that those particular integers also point to strings that can be used in the debugger
Global variables or a singleton will accomplish the same thing here. Both can be used to turn 'key' names in Cocoa that won't throw a compiler error if it's misspelled into a compiler error. That's the main purpose. Global variables are a bit easier though seeing as it requires less typing.
Instead of doing this:
[myArray setObject:theObject forKey:MyGlobalVariableKeyName];
You'd have to do something along the lines of:
[myArray setObject:theObject
forKey:[[MySingletonVariableClass getInstance] myVariableKeyName];
Global variables are essentially less typing for the same effect.
Calling it a global variable is technically correct but misleading.
It is a global constant -- global in scope but constant and therefore not bad in the sense that global variables are bad.
To show how global constants are common, safe and numerous, consider these examples of global constants:
Every class in your program
Every #define
Every enum
Almost every name declared by Cocoa (excluding rare global variables like NSApp).
The only time you should worry about global constants is when their names are too generic (they may pollute the global namespace). So don't use names that are likely to conflict with anything (always use a prefix and always make the name task-specific like NSKeyValueObservingOptionNew).
Constant globals that are set at compile time and never change are acceptable to me. If you hard code a string, it's the same thing, just hidden by the compiler. I'll avoid mutable globals like the plague.
Remember, Apple itself uses the same technique. Many of the constants I expected to be defines are actually constants. You'll get link errors if the headers are reachable but the framework is not.
building on #Barry Wark's and #Matt Gallagher's excellent answers, and my initial response (see end of this answer) there is a third approach, and that is to use a macro/include combination that ensures you only type the variable name once, and therefore it is included in both the .h and .m files simultaneously.
< EDIT >
"there is always another way..."
After thinking about how to make it even simpler, without involving an additional header file, here is a more concise approach using nested macros.
in .h file
#define defineKeysIn_h_File(key) extern NSString * const key;
#define defineKeysIn_m_File(key) NSString * const key = ##key;
#define myKeyDefineKeys(defineKey) \
/**start of key list*/\
defineKey(myKeyABC);\
defineKey(myKeyXYZ);\
defineKey(myKey123);\
/*end of key list*/
myKeyDefineKeys(defineKeysIn_h_File);
in .m file
myKeyDefineKeys(defineKeysIn_m_File);
implementation note
You can use this more than once in multiple headers, however you need to change the
name of "myKeyDefineKeys" to be unique, I suggest giving it the same prefix as the keys you are defining - for the sake of an example I have used "myKey" throughout.
In another file I might use "myOtherKeyDefineKeys".
Also don't mess with the defineKeysIn_h_File and defineKeysIn_m_File macros or you will get a warning the definition has changed.
< END EDIT >
ORIGINAL ANSWER, STILL VALID, BUT WITHOUT REFINEMENTS
First, make a vanilla.h file and remove the default #ifdef etc,and enter your keys as below:
(This is a cut and paste from a category I wrote to extend AVAudioPlayer)
// playFromConsts.h
define_key(AVAudioPlayer_key_player);
define_key(AVAudioPlayer_key_duration);
define_key(AVAudioPlayer_key_filename);
define_key(AVAudioPlayer_key_filepath);
define_key(AVAudioPlayer_key_fileurl);
define_key(AVAudioPlayer_key_urlString);
define_key(AVAudioPlayer_key_envelope);
define_key(AVAudioPlayer_key_startDate);
define_key(AVAudioPlayer_key_linkToPlayer);
define_key(AVAudioPlayer_key_linkFromPlayer);
define_key(AVAudioPlayer_key_linkToPlayerEnvelope);
define_key(AVAudioPlayer_key_linkFromPlayerEnvelope);
define_key(AVAudioPlayer_key_deviceStartTime);
define_key(AVAudioPlayer_key_currentVolume);
define_key(AVAudioPlayer_key_fadeFromVolume);
define_key(AVAudioPlayer_key_fadeToVolume);
define_key(AVAudioPlayer_key_fadeTime);
define_key(AVAudioPlayer_key_segueTime);
Then in your normal.h file (where your #interface, #protocol etc is declared) place these 3 lines (substituting your header file of course)
#define define_key(x) extern NSString * const x;
#include "playFromConsts.h"
#undef define_key
finally in your .m file, that is paired with your "#interface .h" file, place these 3 lines:
#define define_key(x) NSString * const x = ##x;
#include "playFromConsts.h"
#undef define_key
note the "#include" and not "#import" - we actually do want to include this file more than once.
this will do all the dirty work, and ensure the keys are NSString * const.
the trailing ; is optional, as it's included in the macro, however i personally prefer it.
So after all. I came up with 3 files.
Constants.h
#define def_key(name) extern NSString *const name
#define def_int(name, value) extern int const name
#define def_type(type, name, value) extern type const name
#include "ConstantsDefs.h"
Constants.m
#import "Constants.h"
#undef def_key
#define def_key(name) NSString *const name = ##name
#undef def_int
#define def_int(name, value) int const name = value
#undef def_type
#define def_type(type, name, value) type const name = value
#include "ConstantsDefs.h"
ConstantsDefs.h
def_key(kStringConstant);
def_int(kIntConstant, 313373);
def_type(float, kFloatConstant, 313373.0f);
It depends on the design of your software. Suppose you have a job management software and one of your "defaults" is a list of directories in which various items can be saved.
For each Job you can have a storagefile member that is a singleton that load up the user preferred locations at startup.
Or you could have a Storagefile member of a global variable called User Preferences. Still could be a singleton but doesn't really matter in this case.
For me complex defaults (dozens of different types of classes) should reside in their own "space" accessible to model.
However there may be preferences that are important to how a Job is setup so those preference need to be stored in the Job Object so when you open it in another user's application it works as intended.
Again it depends on your design.