How to make NSString macro? - objective-c

How to make a macro that represents a constant NSString value? I'm getting
"Multi-character character constant" and "Character constant too long for its type" warnings when defining in Xcode 4:
#define LEVELTYPEGLASS #"Glass"
Do I need to escape something?

Avoid using defines for string constants. Define as an extern in the header file like this:
extern NSString * const MYLevelTypeGlass;
And them implement in any implementation file:
NSString * const MYLevelTypeGlass = #"Glass";
This gives a few more characters to type, but adds allot of benefits like better typing for Xcode, guaranteed object identity (no duplicate strings). This is how Apple do it, if its good enough for them, it should be good for you.

The solution suggested by PeyloW is great. But I just want to note that I got the solution working after I have added #import "Foundation/Foundation.h" to header file. So the header file Constants.h should look like:
#import "Foundation/Foundation.h"
extern NSString * const LEVELTYPEGLASS;
#define IMAGECOUNT 5
...
Then, implementation file looks like:
#import "Constants.h"
NSString * const LEVELTYPEGLASS = #"Glass";
And if you need to include that into whole project you need to import that in -Prefix.pch file:
#import "Constants.h"
In that case, all the macro definitions resides in Constants.h header file, and some NSString constants resides in Constants.m implementation file. Again, thanks to PeyloW :)

Related

updated advice on setting constants in Objective-C?

I read through the advice here Constants in Objective-C, but I find two errors in the accepted answer:
I keep getting linker errors when I implement the approach of using .m and .h
In my constants.m file, I get the error "unknown type" for NSString
I am also getting an error following the advice from #VictorHanHee
as a further suggestion of how to link the constants to a .pch file:
I don't have a .pch file by default, and when I create a new one it
doesn't have the formatting expected from the answer.
All I have done is create constants.h and constants.m and put the constant declarations in them as provided in the accepted answer. I also created a .pch file, but as I said it doesn't at all match VictorHanHee's description.
Is this older posting outdated, or if not what am I missing? I don't really know how to go forward with a linker error. I simply want to have a file constants.h where I declare all constants and can include this file in as many classes as I want to make life easier. Can someone tell me how to do this nowadays or point to a more recent discussion?
Also here is the linker error (or part of log I can copy and paste anyway, not full message)
-[AccountInfoViewController viewDidLoad] in AccountInfoViewController.o
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)
As you can see, I am trying to access the constant from viewDidLoad. I am simply trying to print it out with NSLog.
Here are the .h and .m files I was originally using:
.h
extern NSString * const PREFS_MY_CONSTANT;
.m
NSString * const PREFS_MY_CONSTANT = #"prefs_my_constant";
Ok here is the template that actually seems to work:
.h
#ifndef Project_prefs_h
#define Project_prefs_h
#endif
extern NSString * const PREFS_MY_CONSTANT;
.m
#import <Foundation/Foundation.h>
NSString * const PREFS_MY_CONSTANT = #"prefs_my_constant";
So the older post is perhaps misleading or I misunderstood them when they said remove everything apart from the constants - but if you don't actually want to remove everything, shouldn't you say so? That's a fair amount of text in there not to mention...
In recent version of Xcode there is no ProjectName-Prefix.pch created automatically file so you should import the file where it is required then try using the constant.
Easiest way:
// Prefs.h
#import <Foundation/Foundation.h>
#define PREFS_MY_CONSTANT #"prefs_my_constant"
Better way:
// Prefs.h
extern NSString * const PREFS_MY_CONSTANT;
// Prefs.m
NSString * const PREFS_MY_CONSTANT = #"prefs_my_constant";
There are a few different ways to create constants in Objective-C, but the easiest way is to use #define statements.
To start, create a new header file. This is where we’ll store all the constants. Name it something original like “Constants.h”.
Here’s a sample file with a few constants:
//
// Constants.h
// App Name
#import <Foundation/Foundation.h>
#define NUM_SECTIONS 7
#define NUM_SECTION_1_ITEMS 2
#define NUM_SECTION_2_ITEMS 14
#define NUM_SECTION_3_ITEMS 5
#define APP_TITLE #"App Name"
#define APP_AUTHOR #"Miscellanea"
To use these constants in your project, you need to import your header file in each implementation file (*.m) where you’ll be referencing them.
#import "Constants.h"
– (void)viewDidLoad
{
self.title = APP_TITLE;
for (int i = 0; i < NUM_SECTIONS; ++ i)
{
// etc.
}
}
Here is the template that does seem to work. It's not different from the old answer except that you don't delete everything apart from the constants.
.h
#ifndef Project_prefs_h
#define Project_prefs_h
#endif
extern NSString * const PREFS_MY_CONSTANT;
.m
#import <Foundation/Foundation.h>
NSString * const PREFS_MY_CONSTANT = #"prefs_my_constant";
Apart from this it appears no longer possible to use .pch file to automatically include the constants across all classes.

Not allowing to use Constant defined in Objective C header file in swift class. Undefined symbols for architecture armv7

I created Objective C Header file. and added some properties in it.
i declared
static NSString* const kColor005C98 = #"005C98"; in Constants.h file
I defined this file in Bridging-Header file as #import "Constants.h"
Now when i want to use this property kColor005C98 in some swift file it failed the build and i am getting
Undefined symbols for architecture armv7: "_kColor005C98", referenced from:
i don't know what else i need to do so i don't get this error? (i have used this property in other objective C file successfully and no issue in that case)
Update:
As of Swift 2/Xcode 7 and later, a static constant definition like
static NSString* const kColor005C98 = #"005C98"; // in Constants.h file
is imported to Swift and can be used without problems.
(Old answer for Swift 1.x) When the code
static NSString* const kColor005C98 = #"005C98"; // in Constants.h file
is processed by an Objective-C compiler, it is treated as two things
combined into one statement:
A variable declaration which introduces an identifier and describes its type, and
a variable definition which actually instantiates/implements this identifier.
See for example
What is the difference between a definition and a declaration?
for a good explanation of the difference between declaration and
definition.
The Swift compiler treats the statement only as a declaration.
Therefore the variable is not defined anywhere, causing the linker error.
To solve the problem, you have to move the definition to an Objective-C
file:
// Constants.m:
#import "Constants.h"
NSString * const kColor005C98 = #"005C98";
and change the declaration to an extern declaration:
// Constants.h:
extern NSString * const kColor005C98;
Alternatively, you can just remove the static modifier:
NSString * const kColor005C98 = #"005C98";
to make it work with Swift. The disadvantage is that when
this line is included by multiple Objective-C files, all of them
will define a globally visible symbol kColor005C98, causing
"duplicate symbol" linker errors.
Another alternative is to use a macro definition instead:
#define kColor005C98 #"005C98"

Use static string from objective c in swift

If in objective c I have a string declared in a header file on it's own, for example
static NSString* my_static_string = #"Hello world";
I am able to use it in swift and Xcode recognises it, however when I try to build I get "undefined symbol _my_static_string ..."
Is there any way I can use this string in swift?
The static keyword, when used with a global, limits the scope of the variable to the current .m file. It's generally used when defining a constant used within a particular .m file, but not to be referenced elsewhere.
It doesn't quite make sense to do that if you're defining a constant in a .h file. In that case, you usually define the variable in one of the .m files:
NSString * const kMyConstant = #"Hello world";
and then in the .h file you define the external reference to this object:
extern NSString * const kMyConstant;
If you use the above pattern, if the .h file is included in the bridging header, you should then be able to use the kMyConstant constant in your Swift code.

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

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
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.
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.
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];
I would create a singleton or use the AppDelegate and put the constants there.
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.

Where to store fixed NSString variables in Cocoa Application?

I have different classes, that have NSString fixed variables (like #"/Users/user/media", or xml commands). I think to store everything in class is a bad design.
What is the best place to store fixed NSStrings? Might something like preferences file?
P.S. I'm new in Cocoa, please describe it with details, how I can store, and read that values. Thanks.
They are many ways, but I like to do this in my class implementation files:
NSString *const ABConstantStringname = #"name";
Where AB is the name spacing you're using (if you are using one), and ConstantStringName is some meaningful name for the constant.
Then later, you can just use the ABNameIdentifier variable whenever you like. You don't release it.
Depends on the scope - if you want to just une in implementation you can just put in .m, but if you want to expose publically to the consumers of the class (outside your .m implementation) you need to also extern it.
In header:
#import <Cocoa/Cocoa.h>
extern NSString* const BNRTableBgColorKey;
extern NSString* const BNREmptyDocKey;
#interface PreferenceController : NSWindowController
{
...
In implementation:
- (id)init
{
NSLog(#"init");
NSString * const BNRTableBgColorKey = #"TableBackgroundColor";
NSString * const BNREmptyDocKey = #"EmptyDocumentFlag";