In my application I want to use some constant strings.
I've created Constant.h and put some values inside:
extern NSString * const CAR_PLAY;
extern NSString * const CONNECTED_TO_CAR_PLAY;
extern NSString * const DISCONNECTED_FROM_CAR_PLAY;
Then, I've created Constants.m file and put the actual value inside:
NSString * const CAR_PLAY = #"CarPlay";
NSString * const CONNECTED_TO_CAR_PLAY = #"Conencted_To_CarPlay";
NSString * const DISCONNECTED_FROM_CAR_PLAY = #"Disconnected_from_CarPLay";
In my AppDelegate I imported Constants.h:
#import "Constants.h"
When I tried to use one of the values for example:
[string isEqualToString:CONNECTED_TO_CAR_PLAY];
I got an error saying Undefined symbol: _CONNECTED_TO_CAR_PLAY.
What is wrong with my implementation? What is the correct way to use constatns?
This seems to work for me:
% cc -framework Foundation -o constants constants.m appdelegate.m
% cat constants.h
extern NSString * const CONNECTED_TO_CAR_PLAY;
% cat constants.m
#import <Foundation/Foundation.h>
NSString * const CONNECTED_TO_CAR_PLAY = #"Conencted_To_CarPlay";
% cat appdelegate.m
#import <Foundation/Foundation.h>
#import "constants.h"
int main() {
NSLog(#"now: %s", [CONNECTED_TO_CAR_PLAY UTF8String]);
return 0;
}
% ./constants
2022-09-14 18:31:58.518 constants[94914:1189470] now: Conencted_To_CarPlay
Related
I was testing some code where I declare a global variable in a header file, but I'm getting a linker error: "duplicate symbol"
header file:
//
// GlobalVaraibleClass.h
// GlobalVar
//
#import <Foundation/Foundation.h>
int gGlobalVar = 0;
#interface GlobalVaraibleClass : NSObject
#end
class file:
//
// GlobalVaraibleClass.m
// GlobalVar
//
#import "GlobalVaraibleClass.h"
#implementation GlobalVaraibleClass
#end
main:
//
// main.m
// GlobalVar
//
#import <Foundation/Foundation.h>
#import "GlobalVaraibleClass.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
extern int gGlobalVar;
NSLog(#"Hello, World! %i", gGlobalVar);
}
return 0;
}
where am I going wrong?
That is backwards, the extern goes in the header, the declaration setting the value goes in the implementation file.
The extern specifies that the variable will be declared somewhere else. If the declaration is in the header every time the header is included there will be another declaration and at link time there will be multiple definitions which will not link.
Example:
// GlobalVaraibleClass.h
extern int gGlobalVar;
// GlobalVaraible.m
#import "GlobalVaraibleClass.h"
int gGlobalVar = 3;
// main.m
#import <Foundation/Foundation.h>
#import "GlobalVaraibleClass.h"
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSLog(#"Hello, World! %i", gGlobalVar);
}
return 0;
}
i was wondering how to access "static" vars from a model from different ViewControllers.
Should I go for:
static vars (if yes, how?)
static method
singleton + method
singleton + variable (custom getters)
#import "CategoryModel.h"
#implementation CategoryModel
-(NSArray*) allSelected {
return [[NSArray alloc] initWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:SELECTEDCATEGORIES_DEFAULTSKEY]];
}
-(NSString*) allSelectedAsUrlParams {
NSMutableString *categoryList = [NSMutableString string];
for (NSArray *category in self.allSelected) {
[categoryList appendString:[category valueForKey:#"value"]];
if(![[self.allSelected lastObject] isEqual:category]) {
[categoryList appendString:#","];
}
}
return categoryList;
}
#end
*Edit (working) *
// header
#import <Foundation/Foundation.h>
#interface CategoryModel : NSObject
+ (NSString*)allSelectedAsUrlParams;
#end
// implementation
#import "CategoryModel.h"
#implementation CategoryModel
+ (NSString*)allSelectedAsUrlParams {
return #"somethingGreat";
}
#end
// How to use
CategoryModel.allSelectedAsUrlParams
This is really going to be a matter of architectural preference, but if more than one class is going to need the static vars, this is one approach:
Constants.h
extern BOOL const TEST_MODE;
extern NSString * const SOME_STRING;
Constants.m
BOOL const TEST_MODE = YES;
NSString * const SOME_STRING = #"SomeString";
As an alternative, you can just add the extern NSString * const SOME_STRING; to the header of class that it is specific to (and the corresponding NSString * const SOME_STRING = #"SomeString"; in the .m) and then call that var directly by importing the header of the class with the constant you need and using SOME_STRING to get at it.
In class A I have this:
static NSString * const kMyConstant = #"my constant string";
How can I reference this from class B?
You should extern your string in the header, and then define the string in the implementation.
//ClassA.h
extern NSString * const kMyConstant;
//ClassA.m
NSString * const kMyConstant = #"my constant string";
//ClassB.h/m
#import "ClassA.h"
...
NSLog(#"String Constant: %#", kMyConstant);
You need to remove the static -- that specifies that kMyConstant is only visible in files linked with this one.
Then, declare (as opposed to defining) the string in Class A's header:
extern NSString * const kMyConstant;
and import that header wherever you want to use this string. The extern declaration says that there exists an NSString * const by the name kMyConstant whose storage is created in some other place.
If the static definition is already in the header, you need to move it elsewhere (usually the implementation file). Things can only be defined once, and if you try to import a file which defines a variable, you'll get a linker error.
If it's static, you can't (that's what the static keyword is for).
If you simply declare it as a global variable, however, you can do something like this:
// ClassA.m
NSString *const str = #"Foo";
// ClassB.m
extern NSString *const str;
NSLog(#"str is: %#", str);
I've seen 2 ways of creating global variables, what's the difference, and when do you use each?
//.h
extern NSString * const MyConstant;
//.m
NSString * const MyConstant = #"MyConstant";
and
//.h
extern NSString *MyConstant;
//.m
NSString *MyConstant = #"MyConstant";
the former is ideal for constants because the string it points to cannot be changed:
//.h
extern NSString * const MyConstant;
//.m
NSString * const MyConstant = #"MyConstant";
...
MyConstant = #"Bad Stuff"; // << YAY! compiler error
and
//.h
extern NSString *MyConstant;
//.m
NSString *MyConstant = #"MyConstant";
...
MyConstant = #"Bad Stuff"; // << NO compiler error =\
in short, use const (the former) by default. the compiler will let you know if you try to change it down the road - then you can decide if it was a mistake on your behalf, or if the object it points to may change. it's a nice safeguard which saves a lot of bugs/headscratching.
the other variation is for a value:
extern int MyInteger; // << value may be changed anytime
extern const int MyInteger; // << a proper constant
I'm trying to create a class with global constants:
//Resources.h
#import <Foundation/Foundation.h>
#interface Resources : NSObject
{
extern NSString * const MY_CONST;
}
#end
and
//Resources.m
#import "Resources.h"
#implementation Resources
NSString * const MY_CONST = #"my constant";
#end
And getting this nasty error: expected specifier-qualifier-list before 'extern'
What do I need to do?
Thank you
put
extern NSString * const MY_CONST;
outside of class interface declaration. MY_CONST is not a class member, so why put it inside?