I want to have a variable that I can access anywhere by importing a header file but I also want it to be static in the sense that there is only one of them created. In my .m file, I specify
static BOOL LogStuff = NO;
and in the initialize method I set the logging value:
+ (void)initialize
{
LogStuff = ... //whatever
}
However I want to be able to access my variable anywhere by importing the .h file so I want to do something like this:
static extern BOOL LogStuff;
but I'm not allowed to do that. Is it possible to do the thing I'm trying to do? Thanks
static in Objective-C means a different thing than static in a C++ class, in the context of static class data members and static class methods. In C and Objective-C, a static variable or function at global scope means that that symbol has internal linkage.
Internal linkage means that that symbol is local to the current translation unit, which is the current source file (.c or .m) being compiled and all of the header files that it recursively includes. That symbol cannot be referenced from a different translation unit, and you can have other symbols with internal linkage in other translation units with the same name.
So, if you have a header file declaring a variable as static, each source file that includes that header gets a separate global variable—all references to that variable within one source file will refer to the same variable, but references in different source files will refer to different variables.
If you want to have a single global variable, you can't have it in class scope like in C++. One option is to create a global variable with external linkage: declare the variable with the extern keyword in a header file, and then in one source file, define it at global scope without the extern keyword. Internal linkage and external linkage are mutually exclusive—you cannot have a variable declared as both extern and static.
An alternative, as Panos suggested, would be to use a class method instead of a variable. This keeps the functionality within the scope of the class, which makes more sense semantically, and you can also make it #private if you so desire. It does add a marginal performance penalty, but that's highly unlikely to be the bottleneck in your application (if you suspect it is, always profile first).
If LogStuff is a static class field, maybe you can implement static getter and setter?
+ (void)setLogStuff:(BOOL)aLogStuff;
+ (BOOL)logStuff;
Declare it extern BOOL in your header file. Files that #import your header don't know or care if the external symbol is static or not.
Separate global variable (one per source file):
// .h
static NSString * aStatic;
//.m
static NSString * aStatic = #"separate";
Unique global variable:
// .h
extern NSString * anExtern;
// .m
NSString * anExtern = #"global";
I normally use this layout for my statics:
NSMutableArray *macroArray;
BOOL keepMacro;
+ (void) startMacro
{
if (macroArray == nil)
{
macroArray = [[NSMutableArray alloc] initWithCapacity:100];
}
[macroArray removeAllObjects];
keepMacro = YES;
}
This is the startMacro command in my application. Both the Bool and the macroArray are static, but notice they are not declared static or extern.
This may not be the best practice, but this is what I do.
Related
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.
I have a static variable that i want to access from another class in the same project in X-Code. I have declared it in the .h file AND the .m file, gave it a value, and then when i accessed the other class, i got an error message saying that:
"Property 'xx' is not found on object of type 'yy'"
i declared the variable as extern in the .h, and redeclared it as the variable type in the .m. I have tried to change it to static in the .h, but it still doesn't work. And yes, i have imported the file containing the variable, in case that is the problem.
Can anyone help me?
EDIT:
this is the code that i'm currently using:
source.h
static int anObject;
#interface source : NSObject
source.m
static int a = 2
#implementation source
destination.m
# include "source.h"
#implementation destination
- (void) anObjectTestFunction
{
printf("%d", source.anObject); //the first version
printf("%d", anObject); //second version
}
now after i went to the second version, the variable anObject in destination.h can be accessed, but its value is not 2, it's 0. I want it to follow the one i declared in source.h.
I am assuming the static variable declared in the .h file is outside the #interface. So something like:
static NSString *myObjectTest = #"Test";
#interface MyObject : NSObject
#end
If that is the case then you will not be able to access it using something like:
MyObject *obj = [[MyObject alloc] init];
[obj myObject]
or
obj.myObject
That is what is giving you the "Property 'xx' is not found on object of type 'yy'". That static variable is not a property on the object of MyObject.
That static variable is accessible like so myObjectTest as long as you import the .h file
Update
See Chuck's comment below why this is a bad idea to do this way.
You seem confused about what a static variable is. In other languages like Java or C++, "static" can mean one of two things. In a file or function scope, it means a variable scoped to either that file or function that exists for your program's entire lifetime. In a class scope, it means just a class variable.
C++ has both definitions, Java only has the second definition, but Objective-C only has the first definition: A static variable can only be used in the place where it's declared. There is no such thing as an "extern static" variable because the two are contradictory. You probably want either a global variable or a static variable with a class method to access it.
Could this be a namespace issue? Try fully qualifying your access. Posting an extract of your code would really be helpful though, I'm no good at clairvoyance :-)
I have an enum defined in the Constants.h file this way:
typedef enum {
CalendarTypeMonth = 0,
CalendarTypeWeek
} CalendarType;
Then in my view controller I determine what the calendar type should be and store it in a property this way:
#property (nonatomic) CalendarType myCalendarType;
Now I want all the classes in my project have access to the calendar type. How can I set this property to be global/extern so that all classes can read this?
EDIT: I know the definition of the enum will be available across the project. But what I am interested in is the value of myCalendarType. How can I access the value of myCalendarType across all classes?
You can declare class method to access static variable.
Add such code to your implementation file:
static MyStaticType staticVar = MyStaticTypeDefault;
+(BOOL)myStaticVar
{
return staticVar;
}
+(void)setMyStaticVar:(MyStaticType)newValue
{
staticVar = newValue;
}
And create declarations for this methods in interface file.
This is much better then moving all static values to AppDelegate.
Anyway, a lot of variants are possible - for example, you can create singletone to store some settings of application or use CoreData.
In your [Project Name]_Prefix.pch file, you can add this statement:
#import "Constants.h"
In so doing, you'll make your enum available to every file in the project.
EDIT:
To access the value, I suggest making it a global property of your application delegate. To take it a step further, you can make your application delegate a method of NSObject using a category so it might look something like:
CalendarType current = [self appDelegate].currentCalendarType
Observe that your property is now a globally gettable/settable property.
// in ClassA.h
static NSString *globalStr = #"HelloWorld";
#interface ClassA
...
#end
// in ClassB.h
#include "ClassA.h"
// in ClassB.m
...
NSLog(#"The global string: %#", globalStr);
...
In C++, "static" should mean the variable or function has a internal linkage.
But it is used to share the variable in this case, error will occur without the static keyword.
I'm confused, could someone tell me the concept behind?
Thanks!
static means exactly the same thing in Objective-C that in means in C - it has internal linkage and static storage duration. You get an error without the static in this case because you will have a duplicate symbol globalStr in each object whose source code included ClassA.h. You're not sharing anything - you're getting a new copy of globalStr for each compilation unit.
Don't put object definitions in your headers and you'll be better off. If you want a single global string, you need to put
extern NSString *globalStr;
In ClassA.h, and define it in exactly one implementation file as:
NSString *globalStr = #"HelloWorld";
I don't quite understand static variables when defined in the implementation of an interface. In methods I do understand how they differ from local variables, but not when defined directly in an implementation.
Look at these examples. What difference do these two make practically?
#include "MyClass.h"
#implementation MyClass
int myInt;
...
#end
And:
#include "MyClass.h"
#implementation MyClass
static int myInt;
...
#end
myInt is in both cases visible to all the methods, and if I interpreted a test I ran correctly, myInt will in both cases be the same variable for different instances of the class.
Unfortunately, it has different effects depending on where you use it.
Static Functions:
By default, all functions have a global scope. The static specifier lets you limit the function’s scope to the current file.
Static Local Variables:
When you use the static modifier on a local variable, the function “remembers” its value across invocations. For example, the currentCount variable in the following snippet never gets reset, so instead of storing the count in a variable inside of main(), we can let countByTwo() do the recording for us.
// main.m
#import <Foundation/Foundation.h>
int countByTwo() {
static int currentCount = 0;
currentCount += 2;
return currentCount;
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSLog(#"%d", countByTwo()); // 2
NSLog(#"%d", countByTwo()); // 4
NSLog(#"%d", countByTwo()); // 6
}
return 0;
}
This use of the static keyword does not affect the scope of local variables.
Read more about the static keyword.
The 'static' keyword in that context is the same as it would be in plain C: it limits the scope of myInt to the current file.
"In both C and Objective-C, a static variable is a variable that is allocated for the entire lifetime of a program. This is in contrast to automatic variables, whose lifetime exists during a single function call; and dynamically-allocated variables like objects, which can be released from memory when no longer used. More simply put, a static variable's value is maintained throughout all function/method calls. When declared outside of a function, a static variable is visible to everything within the file in which it is declared; when declared inside a function or method, it is visible only within that function or method, but the value is retained between calls."
Check out the complete explanation here:
https://stackoverflow.com/a/4965145/951349
From Apple's "The Objective-C Programming Language": "Declaring a variable static limits its scope to just the class -- and to just the part of the class that's implemented in the file. (Thus unlike instance variables, static variables cannot be inherited by, or directly manipulated by, subclasses)."