In the header of the class, outside of interface declaration, I've declared global constants:
NSString * const gotFilePathNotification = #"gotFilePath";
NSString * const gotResultNotification = #"gotResultOfType";
gotResultNotification is used only in this class (yet), but I reference gotFilePathNotificaion in another class implementation. To do it, I import this header.
When I try to compile, I get a duplicate symbol linker error about gotFilePathNotification in this header. Why does it happen?
You have two identifier(s) with same name across two different compilation unit(s) at file scope. This violates One Definition Rule. Instead you need to -
Declare the global variables marking to have external linkage in a header file.
extern NSString * const gotFilePathNotification;
Now provide the definition in only one source file.
NSString * const gotFilePathNotification = #"gotFilePath";
Now where ever you need to use these variables, include the header in the source file.
You need to declare them extern in the header file and define them in implementation file. See this question for clarification. Global Variables in Cocoa/Objective-C? .
The second response provides the clarification that I will reiterate here. The default storage qualifier for variables is static. This means when you try to link two different files with the same variable, as will happen when you import your header file, the linker will construe that the variable is multiply-defined.
Also make sure you're including the h file and not the m file. This was driving me nuts.
Related
I have an error that used to look like this in Objective-C
NSString * const JKConfigurationErrorDomain;
typedef NS_ENUM(NSInteger, JKConfigurationCode) {
JKConfigurationCodeUnknown,
JKConfigurationCodeSomethingBad,
JKConfigurationCodeParsing,
};
Now, this is ugly to use in Swift. But since Swift 4, we can use NSErrorDomain and NS_ERROR_ENUM to make the imported error much nicer in Swift:
NSErrorDomain const JKConfigurationErrorDomain;
typedef NS_ERROR_ENUM(JKConfigurationErrorDomain, JKConfigurationCode) {
JKConfigurationCodeUnknown,
JKConfigurationErrorSomethingBad,
JKConfigurationErrorParsing,
};
This means I can now do stuff in Swift like this:
if let myError = error as? JKConfigurationError, myError.code = .somethingBad {
// handle it
}
instead of having to cast error to NSError, then check its .domain then look at the .code which is an integer, etc.
So far, so good. But my library is called JKConfiguration and there is already a JKConfiguration object (the center piece of the library) in there and as soon as I start using JKConfiguration anywhere in the library code I get an error:
'JKConfiguration' is ambiguous for type lookup in this context
I don't get it, why? What does NSErrorDomain or NS_ERROR_ENUM do such that the type lookup becomes ambiguous and how can I fix it?
What I tried already:
use NS_SWIFT_NAME on the NS_ERROR_ENUM typedef and rename it to something else. Looking at the generated Swift header, the rename works, but doesn't solve the issue
Change the name of the error domain (and thus of the generated error type in Swift). Seems to work according to the generated Swift header, but the issue still persists. Why is that?
The issue is not, as I initially thought, in the name of the error domain. Nor is it a problem with the library name. It’s a problem of the error enum‘s name, in the example above: JKConfigurationCode.
What the Compiler does for the enum cases of an NS_ERROR_ENUM is two-fold:
use the name of the enum and remove that prefix from all enum cases before importing them to swift
create an enum with the given name to hold those cases. If the given name ends with Code remove that suffix.
So that last part is the issue. It means that NS_ERROR_ENUM(AnyDomainName, JKConfigurationCode) generates an enum in Swift to hold the error codes with the name JKConfiguration (without the Code) prefix. But that type already exists in my example, which leads to the ambiguity.
So the solution is to change
NS_ERROR_ENUM(JKConfigurationErrorDomain, JKConfigurationCode)
to
NS_ERROR_ENUM(JKConfigurationErrorDomain, JKConfigurationSomethingCode)
Or similar.
Don’t forget to update all the prefixes of your enum cases though, as it seems the compiler won’t find them if the prefixes don’t match the enum name.
Why doesn’t NS_SWIFT_NAME work to rename the enum?
Best I can tell, NS_SWIFT_NAME causes the type to be renamed but not the cases. This leads to an empty type (Swift chooses a struct in that case) being generated for the error code as Swift doesn’t seem to find the cases. And the original container for the enum cases still has the offending name.
Using objective c , I have 2 classes that are using hardware, and are written in c +objC .
The other classes in the project are objective c, and they create instance of those classes.
My question .
Lets say I have classA.m and classB.m . they both have an integer const that needs to be the same say : const int numOfSamples=7;
I am seeking for the best solution to create some configuration file, that will holds all this const variables, that both A and B can see them .
I know some ways,but I wonder whats the RIGHT thing to do .
I wonder if I can just create a : configuration.m and write them into it .
to use a singleton file that holds all globals .
Number 1 seems to me the best , but how exactly should I do it ?
Thanks.
For approach 1 to work, you need to define two files:
a header file where you declare all of your constants;
a .m file where your constants are defined and initialized.
In your example:
/* .h file */
extern const int numOfSamples;
/* .m or .c file */
const int numOfSamples = 7;
Then, you include the .h header in every other file where you need those constants. Notice the extern keyword, this will declare the variable without also defining; in this way, you can include the .h file multiple times without having a duplicate symbol error.
EDIT:
The approach I suggest is the correct way to handle global variables in a C program.
Now, if global variables are a good thing or not, well, that is a longer story.
Generally speaking, global variables are tricky and go against a 40 years long effort towards better encapsulation (aka, information hiding) of data and behavior in a program (see "On the Criteria to Be Used in Decomposing Systems Into Modules", David Parnas, 1972).
To further explain this, one aspect of the problem is exactly what you mention in your comment: the possibility of one module changing the value of a global variable and thus affecting the whole behavior of the program. This is recognizedly bad and leads to uncontrollable side effects (in any non trivially sized program).
In your case, I think things are a bit different, in that you are talking about "configuration" and "const" values. This is an altogether different case than the general one and I think you could safely use a header file of consts to that aim.
That said, you understand that the whole theme of configuration is a huge one, in general. E.g., you could need mechanisms to change your program configuration on the fly; in this case the constant variable header approach would be not correct. Or, your program configuration could depend on the state of some remote system (imagine: you are logged in vs. you are not logged in).
I can't guarantee that using a header file is the best approach for your case, but I hope that the above discussion and the example I gave you can help you figure that out.
I think the best way is to use a plist file with all your configuration values.
If you have few configuration values, you can use the Info.plist file.
I am curious to know if there is any way to find a global variable at runtime, much like NSClassFromString. The variable, a BOOL, is defined in a static library and I found the name by using "nm" which gave this output: "0001924d b _gStartSessionCalled". When debugging in XCode I can add an expression "gStartSessionCalled" and see the value change as the app is running.
What I want to do is find the value of gStartSessionCalled and also change the value. I know it's kind of weird to do this but please disregard the reason why.
The lowercase letter "b" in the nm output
0001924d b _gStartSessionCalled
indicates that gStartSessionCalled is a local (non-external) symbol. It could for example be defined as
static BOOL gStartSessionCalled;
in your library. As far as I know, you cannot access local symbols from outside the object file in which it they are defined.
The debugger can use the symbol table to find the address and display the variable, but the linker refuses to link against a local symbol from a different object file.
A global variable is not an Objective-C specific construct. It is plain C and you can access every global variable when knowing its name by declaring it like
extern <type> <name>;
e.g. in your case
extern BOOL gStartSessionCalled;
…
gStartSessionCalled = YES;
Update:
If you do not know the name of the variable at compile time, you still may find the symbols address at runtime using something like dlsym. I don't know if it is the same on MacOS as on Linux, but there will be something similar.
In my game I have a header file that contains properties and functions for seasons in my game. These properties are all static and include a float representing the current season and another float representing the current point in the transition between seasons, being zero if it isn't transitioning.
Several functions throughout my game rely on the transition (two at this point) and one is working perfectly. Although, in another instance this isn't working at all.
In the class responsible for controlling the background for my game, when ever the "SeasonTransition" variable is referenced it just comes up zero. But in the other class, where the variable is referenced exactly the same way, it comes up with the real value.
This is a picture after a breakpoint has been called after the game could update a few frames:
Once again these variables are declared in a c header file:
#import "somestuff.h"
static float SeasonTransition
etc...
This shouldn't be doing this right? How could I fix this?
EDIT:
The Season.h file is as follows:
//GL.h contains different functions and global variables to be used anywhere in the project.
//This file, like Season.h is a singular header file with static declarations, and is setup
//the same way. I have been developing this from the start of the project and havent had any
//problems with it.
#import "GL.h"
static float currentSeason;
static float SeasonTransition;
static void UpdateSeason(){
currentSeason += 0.0002f;
float TransitionLength = 0.15f;
float SeasonDepth = Clamp(currentSeason - floorf(currentSeason), 0, TransitionLength);
float bigTL = TransitionLength / 4;
float endTL = TransitionLength;
float Speed2 = 0;
float Speed1 = 1;
float bRatio = SeasonDepth / bigTL;
float eRatio = SeasonDepth / endTL;
SeasonTransition = (SeasonDepth < TransitionLength) ?
((SeasonDepth < bigTL) ?
(Speed1 * bRatio) + (Speed2 * (1.0f - bRatio)) :
(Speed1 * (1.0f - eRatio)) + (Speed2 * eRatio))
:
Speed2;
}
If you put static float SeasonTransition; into two separate C files (or one header file included by two separate C files), each C file will have its own independent copy of the variable.
If one of those C files then modifies the variable, it will modify its copy. It will not touch the one in the other C file. That sounds like the situation you're in.
The normal way to do this is to define the variable in one and declare it external in the other, something like:
file1.c:
int myVar; // it exists here.
file2.c:
extern int myVar; // it exists, but elsewhere.
You don't want to mark it static in the first since that effectively makes it invisible to the second. And you mark it extern in the second so that it knows the variable exists elsewhere (in the first).
You would actually see the effect if it weren't static. When the linker came to link those two files together, it would complain about having two variables with the same name.
There are many variations on how to do that, I've shown the simplest. It's probably better to have something like:
file1.h:
extern int myVar; // so everyone knows about the variable
// just by including this.
file1.c:
#include "file1.h" // or import for ObjC.
int myVar; // the actual variable.
file2.c:
#include "file1.h" // now we know about it, in the OTHER C file.
I could be wrong but I think the problem might be you don't quit understand how include/import work. These are not quit language features but preprocessor feature. When you include somewhere in a file, your say take the entire contents of that other file and stick it in here before your start compiling. So if you include the same header file in multiple different other files you will end up with multiple version of that static variable, with out the static you will get a compiler error because you have redefined the same variable multiple times. import works almost the same except if the preprocessor determines that the included file has already be include into the destination file (could be indirectly through another include), then it will not include the file again. If you understand this you can then see that declaring static variable within you header is quit strange, because you will end up with multiple versions of that variable everywhere that header is included. Normally you want to make the variable global in which case you define it in a .c or .m file and then declare it extern in the header or you want the variable to be private then you declare it static in the .c or .m file.
What static does is to hide the variable declaration from the linker, so the linker can not recognise that all the different declarations of the same name should be treated as the same variable.
#ifndef Season_h
#define Season_h
... your header stuff
#endif
Also, if you dont call updateSeason seasonTransition will be zero.
I have a .h file that defines a few hundred constants. Let's assume this to be one of them:
#define KDSomeItem 1
I know that the Objective-C runtime API can be used to retrieve a list of instance variable names: like detailed in this question: How do I list all fields of an object in Objective-C?
I also know that the getter [object valueForKey:theName] can be used to access the ivars as found in an earlier question of mine: How to access a property/variable using a String holding its name
My question is can something simmilar be done with constants? That is can I:
a) get a list of all constants programmatically
b) access a constant if I have a string holding its name
e.g. if I had a String like this NSString * theName = #"KDSomeItem"; could I evaluate my constant using this string?
You would not be able to do this: unlike instance variables, #define-d constants do not leave a trace after the preprocessor is done with them. They leave no metadata behind - all instances of KDSomeItem in the body of your program will be replaced with 1 even before the Objective C compiler proper gets to analyze your code.
If you need the constant names to be available at run time, you would need to build all the necessary metadata yourself. In order to do that, you may want to look into "stringizing" operator of the preprocessor:
#define STR(X) #X
This macro can be applied to a preprocessor constant, and produce a C string literal with its name:
const char *nameOfKDSomeItem = STR(KDSomeItem); // same as "KDSomeItem"
Nope. Your constant is a preprocessor macro. It is textually substituted into your source code where you use it.