Swift - Variables in different files - ios

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.

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.

Trouble putting data into global variables

I have several method implementations that need access to the same variables. For example, I have a variable that I am placing a user's first name in, and I need to be able to access this variable in all of my various method implementations inside the same View Controller.
I have created a custom class called "PotentialFriend" which is a subclass of NSObject. PotentialFriend's header file also contains an NSString property called "name".
In my view controller's header file I have created an instance of my PotentialFriend class called "potentialFriend". I can successfully type "_potentialFriend.name" in the View Controller's main file, but if I set it to equal something like #"Steve" it shows as (null) in the console.
However, if I do the following, and actually initialize a local variable, I can successfully get the variable to hold the data:
PotentialFriend *potentialFriend = [[PotentialFriend alloc]init];
potentialFriend.name = #"Steve";
But this doesn't work for me because I have another method implementation in this VC that sets up the UITableView's settings and I need to be able to access the value of "potentialFriend.name".
The only way I know how to do this is with global variables, but like I said I can't get the global variables to actually hold the data.
Any ideas why I can't get the global variables to work?
EDIT:
I just went and ran a test. I created an NSString object in my View Controller's header file, and was able to successfully get it to hold data as a global variable like this:
_potentialFriendz = #"Steve";
So it must have something to do with the fact that I created my own custom class called PotentialFriend, but I still don't understand why that isn't working.
It sounds like you aren't allocating and initializing an object for potentialFriend. Just declaring it as a property in your header doesn't instantiate an object inside of it. It is just a property that can hold an object of the specified type.
You need to do something like:
self.potentialFriend = [[PotentialFriend alloc] init];
in viewDidLoad: or at some other initialization method (like initWithCoder:)
In other languages, setting potentialFriend.name without an instantiated object would throw some kind of exception or something, but Objective-C allows sending messages to nil (you are doing the equivalent of [potentialFriend setName:#"string"] when you use the dot-syntax).

How to set values to a class without creating an instance of class?

Currently I have 2 ViewController files I want to share common data between, however I want to have a class called GlobalVariables store all of the variables throughout my code. In one of the ViewController files, I want to set the value of a variable (I have created a setVariable method in the GlobalVariables.m file) and from the ViewController, I want to call this method so it sets the variable. How can I do this without creating an instance of GlobalVariables as any changes I make to the instance will not carry over when I create another instance of GlobalVariables in my second ViewController file?
Use singleton Design Pattern. It’s an extremely powerful way to share data between different parts of code without having to pass the data around manually. And also it will always be a single instance through out the Application life cycle
Please check this link:
Singleton Class
Define your varible in AppDelegate. AppDelegate is a Singleton class.
And access that variable where you want.
It's unclear what you mean by "set values to a class". There are 3 kinds of variables in Objective-C: global variables, instance variables, and local variables. Local variables are not relevant. If you con't want to create an instance, then instance variables are out. So then you want global variables. They can be set and accessed by any function or method.

iOS: understanding global variables

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.

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