iOS: understanding global variables - ios

In my first ViewController ViewControllerTest1 I've got a global variable called counter.
counter is supposed to be increased every now and then in my app. Everything works fine:
#implementation ViewControllerTest1{
int counter = 0;
-(void)viewDidLoad
{...}
-(void)method {...}
}
Now if I declare another global variable called counter in my second ViewController ViewControllerTest2 XCode gives me an error.
I know I can just give it a different name, but why does that happen? Can I make sure only the globals of the certain ViewController that is active are in my memory?
Or am I doing something like a no go right now with globals like counter?
Is there something better?

If you want a symbol to be specific to a file, use the static keyword when declaring it.
Your declaration should look like
static int counter = 0;
At link time (after all the files were compiled), the global symbols are mixed up in the same file, and therefore, if two share the same name, an error is fired by the linker.

If you define a variable at file scope (which includes locations within a class definition but outside the ivar area or a method body), it will have extern linkage by default, which requires unique symbol names.
Make it a static variable (static int ...) and the problem will be resolved, because static symbol names only need to be unique within the file in which they are declared.
If you are accessing this variable outside this file intentionally, and so need to maintain extern linkage, you will need to name the other variable something else to distinguish the two.

Related

Scope NSArray in Objective-C

In GLViewController.m file
At the very top of Implementation
NSArray* imageArray ;
Then in GLViewController.m inside GLViewController
- (id)initWithCoder:(NSCoder*)coder
{
imageArray = #[ #"baban.jpg",#"cete.jpg",#"cipan.jpg",#"kuc.jpg"];
}
Inside drawView in GLViewController.m
NSLog(imageArray[0]); //Fails
I've got it declared in the GLViewController.h file too:
NSArray* imageArray;
I am including GLViewController.h in the GLViewController.m
Your question is not clear. E.g. have you declared imageArray as an instance variable, a global variable, or possibly both – "At the very top of Implementation" could be read as "top of file", "top of implementation just below #implementation in braces" etc.
So we're guessing, let's hope it helps.
First, from what you report; that the init runs but in and instance method accessing the instance variables "fails" in some non-specified way; you may have two different variables declared in different scopes. Without a minimal reproducible example we can't be more specific. What you can try is to insert:
NSLog(#"Loc A imageArray #%p = %p", &imageArray, imageArray);
in various locations, where you change the "A" (to "B", "C"...) for each one, where you are accessing imageArray. This will print the address of the variable itself, from which you can determine whether you are always referring the same variable, and the variable's contents as an address, from which you can determine if the value is changing i.e. whether it's nil or the array it references has changed.
Second, you write "I've got it declared in the GLViewController.h file too". You normally do not declared instance variables in the .h file, though you can, and you do not re-declare global variables in a .h and doing so should produce a compiler error – you don't report such an error which leads to the possibility covered above that you may have two variables in different scopes.
If you wish to declare a global variable in file.m and have it accessible to other code in a different file then in file.h you include an extern declaration for it:
extern NSArray* imageArray;
The extern states that this line is not declaring the variable itself but that the variable is declared elsewhere and accessible. (You might wonder why you don't add extern to functions/methods, in those cases the extern is implicit.)
Hope that helps in some way. If this doesn't help at all I suggest you ask a completely new question providing more detail, the minimum reproducible example, etc. (If you edit this question now people may miss the edits thinking they've seen the question.) You can always delete this question to reduce clutter.

Swift - Variables in different files

I am developing a game in Xcode with Swift.
In my 'SPSwipes.swift' file, a variable is given an initial value. However I have looked all around the internet to find out how to modify that variable in my GameViewController, but I can't find anything. Apparently there is no need to 'import', so how do I access that variable in a different file?
Thanks, Will
First you have to be sure that the variable has not been declared as private.
If the file where the variable is declared and the file where you are trying to use the variable are in the same module, then there's nothing special to do - just reference the variable from the other file, and it has to work.
If the variable and the source where you want to use it are in different modules, then the variable must be declared as public and you have to import the module in the file where you want to access it.
I presume your case is the first. If still doesn't work, it would be good to know how you have defined the variable and how you are trying to access to it (which means, share some code).
in one file called otherFile.swift , I have
class otherFile: NSObject {
var str:NSString = "hi"
}
and in the next file I have
println(otherFile().str)
this works, make sure you instantiate the object first
In one file, declare a variable like normal:
var str = "Value2"
In the other file, access the variable like any other:
print(str)
str = "Value2"
Swift variables are global.

why doesn't setting a static variable to nil defeat purpose of static variable? [duplicate]

This question already has answers here:
What makes a static variable initialize only once?
(4 answers)
Singleton objective c clarification
(5 answers)
Closed 8 years ago.
The code below is from the Big Nerd Ranch iOS programming book, 3rd edition. It's a class method that checks whether the singleton class BNRItemStore has been instantiated. If it has, it returns the singleton instance, and if it hasn't it creates it. The part I don't understand is the static variable. I know that static variables keep state, however, wouldn't calling the method a second time reset the *sharedStore back to nil? i.e. isn't this an assignment which would erase the creation of the singleton instance once the method was called again?
static BNRItemStore *sharedStore = nil;
Method
+(BNRItemStore *)sharedStore
{
static BNRItemStore *sharedStore = nil;
if (!sharedStore)
sharedStore = [[ super allocWithZone:nil ] init ];
return sharedStore;
}
Unfortunately, C terminology is really confusing. static has nothing to do with singletons, standing still, not changing, or anything like that. It has to do with the level at which storage takes place.
A variable declared inside a method/function is normally an automatic variable, meaning that it goes out of existence when the scope ends (i.e. execution reaches the end of the surrounding curly braces). A variable declared static, however, is stored at the level of the file that holds the code; once the file is loaded, this variable persists, even though it is declared inside a method/function.
Now we come to the question of how you will know whether this variable has ever been assigned a value, because you only want to assign it once. In theory, a static variable has a zero value when it is initially declared. Thus, if you said merely
static BNRItemStore *sharedStore;
...the code might work, because zero is nil for an instance, so we could test against nil and assign a value only in that case. However, it does no harm to make assurance double sure. Thus, we typically initialize the variable to nil when we declare it, just so we can be sure our nil test will work the first time.
That initializer, as you've already been told, will then take effect only once, because after that, the value persists and so the variable never needs to be initialized again (and never is).
The code is fine, the initialiser only gets called the first time.
Static initializers are guaranteed by the language specification to only be executed one time, (and that's actually done at application start time, not as a part of function execution) so the static variable will only be nil the first time the function is executed.

Clear Unused Entity Warnings For Static Int In xCode

I have a project, with a file that I call 'Keys.h'
In that file, I declare strings and integers that are used across the project, some of which are integers, some of which are strings.
All of the strings work fine; however, if I use integers, I get an unused variable warning.
For a string, (lfPrefs is a dictionary of user preferences)
static NSString * kUserLFPrefs = #"lfPrefs";
This works fine, and does not produce any errors.
For an integer, (I have integers to define the current mode because it seems a bit snappier than comparing strings all the time).
static int kModeLiveFeed = 1001;
static int kModeEventFeed = 2002;
These work just fine, except that they are showing an unused entity warning.
I'd prefer to use the integers over strings, mostly because I read that comparisons are much faster, takes up less memory, etc.
My question is how can I stop the warnings while still getting access to my integer keys?
(Or, should I just use strings)
I can suggest two different methods.
If you want to keep such variables in .h file, you may prefer using define if you will not be changing the value run time like;
#define kModeLiveFeed 1001
If you will be changing the variable value run time, I suggest keeping them in a .m file instead of in a .h file and creating only one instance of the .m file by using singleton. Then, even if you continue to get a warning from the .m file, you can disable it by the steps below:
Select your project from the left navigator to open project settings view.
Then, select your target.
Go to Build Phases tab and open compile resources area.
Click to the right side of your .m file to add a compiler flag as -w
I hope it helps.
You may be misunderstanding the meaning of static in C/Objective-C (this question should help). You should use const rather than static to define constants, and you should define the value of an integer/string constant in a .m file, with a corresponding declaration in the .h file. Or better yet, use an enum if you have a related set of integer constants.
Here is Apple's documentation on constants, which includes the above information as well as naming recommendations (e.g., PRConstant is preferred over the classic Mac OS-style kConstant).

getting value of global variable from .m to another .m

I have tried getting value of global variable from .m to another .m in 2 ways :
Firstly, I tried to import the viewController.m class in another .m class and tried to retrieve the value but I received a linker error.
Secondly, I simply created extern with the string name and then it started working perfectly.
My question is Why import gave me the error and how extern variable recognizes the string name from that particular class ?
( ie : What if I had 2 or 3 variables with the same name in different classes and I type extern and string name which value would I get since I am not importing any class.)
And, Add-on question : When DO you really import the class ?
You really import a class when you need access to it's properties and methods. That might have sounded too obvious, but that's what it really is. Classes are OOP's encapsulation concept personified.
Getting a variable from one point to another can be done in many ways, one could use the userdefaults facility, you could have the variable within the app delegate and then access the value in different classes or you could expose a property on your destination view controller and have the source view controller set that property before transitioning to the destination..to name a few. There are many more methods that are right and wrong depending on the scenario.
Importing a view controller A into another view controller B, simply to have access to a value in A seems like overkill (if not flat out an inappropriate use of the importing mechanism).
This question explains externs further, I have no exposure to them,
Objective-C static, extern, public variables
Hope this helps.
Firstly, I tried to import the viewController.m class in another .m
class and tried to retrieve the value but I received a linker error.
You NEVER import a .m (implementation) file. You only ever import .h (header) files.
My question is Why import gave me the error
In C, there is a rule that any (non-static) global function or variable with a certain name must be defined only once. For a variable, writing its type and name defines it. For a function, the implementation defines it. Thus, having global functions or variables of the same name in two different code files will fail. They will conflict.
Importing a file means take the entire source of the file and insert it there. When you "import" A.m into B.m, the entire source of A.m is inserted into B.m. That means every declaration in A.m now shows up in two code files in your program -- A.m and B.m, hence the error.
You can declare (but not define) a global variable or function more than once. You can declare a variable by using extern without defining it. Declaring it with extern allows you to use a variable even though it is not actually declared in the same code file.
and how extern variable
recognizes the string name from that particular class ? ( ie : What if
I had 2 or 3 variables with the same name in different classes and I
type extern and string name which value would I get since I am not
importing any class.)
As explained above, you can only have one non-static global variable with a given name in your program. It would be an error to have variables with the same name in different files. It is possible for non-static global variables and functions to be accessible from any other part of the program, by its name (and it works through the magic of linking).
Generally, the best practice for a global variable that will be used in many files, is to define it in a .m file (as you're doing), and the declare it extern in the .h file corresponding to that .m file. Then other files that import that header will automatically have access to that variable.
I know this has already been answered in detail, but I just want to offer some clarification.
Declare data that you want to keep private in your .m file. For data that you want to make accessible to other objects, declare in your header .h file. Use properties for all your declarations:
//myViewController.h
#interface myViewController: UIViewController
#property (assign) int myInt;
#property (strong) NSString* someString;
#end
You can access these properties from another object by passing a message to myViewController:
[myViewController setMyInt:20]; //setter
[myViewController someString]; //getter
Or you can use the equivalent dot notation
myViewController.myInt = 20;
myViewController.someString;
(you need to #include "myViewController.h" in any object that wants access to these)
Inside myViewController you access them using 'self':
self.myInt;
self.someString;
This is mediated access via the setter/getter. The backing variable can be accessed directly from inside myViewController (but not from any other object) as _myInt, _someString. This is not advised outside of init and dealloc methods.
A property encapsulates declaration of instance variables and creation of default getters and setters, so you do not need to make a separate variable declaration, and you only need to make your own accessors if you need to change the default behaviour.
Please also refer to my answer here:
Should I declare variables in interface or using property in objective-c arc?

Resources