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?
Related
NOTE: I am only talking about .m file here.
I am confused by these two things, both are said to be the way to declare internal instance variable:
Way 1:
#interface MyClass ()
// Declare instance variable which is only visible in this class
#end
#implementation MyClass
...
#end
Way 2:
#implementation MyClass {
// Declare instance variable which is only visible in this class
}
...
#end
What are the differences between these two ways of declaring instance variables?
In terms of functionality, there is no difference.
Declaring the ivars in a class extension -- the #interface MyClass() {...ivars...}#end pattern -- does allow you to move the ivar declaration to a header file that could then be used by other classes for direct access for internal-only use, for example.
After the "#interface" line, you can add instance variables within curly braces. That's instance variables, not properties. After the curly braces, or immediately after the "#interface" line if you have no curly braces, you add methods and properties.
So your first comment is wrong. Instance variables can only be added within the curly braces. Properties generate instance variables (usually but not always), but they are not instance variables.
Besides ivar, properties also generate setter and getter method if necessary (according your property attribute). But if you implement the setter and getter synchronously, compiler would not synthesize ivar, since the compiler will assume that you are taking control over the property implementation and won’t synthesize an instance variable automatically.
In Objective C the { } it’s the area where you declare instance variables. You can also use access member declaration in that section like #private #public & #protected. When you declares the "ivars" outside the {} the variable will be a file-scope variable (kind of static) and it won't be an instance variable of your class.
If you use properties (#property) the compiler is smart enough and will create its own ivars with its corresponding setter and getter.
Using a class extension in the implementation file allows you to add ivars or properties (and methods) that are only accessible by the implementation of the class extension. It also allows you to overwrite access of base classes like properties or private methods.
I have noticed in many of the header documentation files in the Apple framework that define variables within brackets directly following the interface definitions like the variables a and b below:
#interface MyView : UIView {
#package
int a;
UIView b;
}
Normally I have just been declaring all variables as properties for the convenience of the synthesized methods. Can anyone tell me when it would be more efficient or more proper to declare variables under #package instead of as #properties?
#package is an access specifier, similar to how it works in Java (it allows access from any code at the same package level). But since the . syntax with Objective C objects works with properties, and not direct member access, you have to use the -> syntax instead, as if the object were a C struct, to access that variable directly.
An auto-synthesized #property instead creates a protected instance variable (prefixed with an underscore), which is read and set by the synthesized methods. Now, the overhead of using a property is negligible, compared with direct member access, so there's no real reason to stop using properties.
In your example, if you had a MyView* myview, you could set the view b directly, with myview->b = someotherview;. But this would give the class no chance to respond to the update (you would probably write the setter method so you can do something with it), nor does it ensure that the view provided is retained properly. These are the issues that properties were designed to avoid.
If some one can brief on declaring instance variable inside .h file inside #interface braces and in .m file #interface braces. like this below
#interface ViewController : UIViewController { NSString *str ; }
#interface ViewController () { NSString *anotherStr ; }
Thx
There's even a third place where you can define instance variables: at the implementation statement:
#implementation ViewController { NSString *yetAnotherString; }
AFAIK, in the olden times you could only define the instance variables in the main interface. The other two places were added later. You can also mix them (as long as they have different names).
The advantage of defining the variables at #implementation and also the class extensions #interface ViewController () level (when done inside an .m file) is that you can hide implementation details from users of your API. In other words, if someone reads the .h file (s)he doesn't know about the variables. This makes the visible API cleaner and is also a concept called "information hiding" which is quite important in object oriented programming: don't expose too much implementation details so you can change the implementation without breaking code using the class.
Note that you can also define IBOutlet variables at all three levels and Interface Builder will detect and use them!
So when you're deciding where to define the variable you can simply ask yourself: Do other people need to see the variable when they see the .h file? IMHO this is only true when you need/want to make a variable #public. For all other cases, you can define them at the class extension or implementation level to make the API cleaner.
Whatever you declare in ViewControllerA.H is public. It means that other view controllers that contain the ViewControllerA object can access use the methods or variables directly. Whatever you declare in .M is private, other view controller can not access it immediately.
As for my own practice, most of the variable (I don't use much) or properties I declare in .M to prevent other view controller to access it directly. It is just like one concept in Object Oriented Programming - Data Encapsulation.
Note: Please be reminded that this should not be confused with #public, #protected, #private like DarkDust mentioned below. It will be another different topic.
In objective-C while you declare the member in .h file, it becomes visible to the other file when .h file is imported as header.
By default all member variables are private. So, user can not use them directly. But with methods of runtime.h and setValueForKey give them an alternate way to set those variable.
To avoid the user to do such mischief, its advisable to declare your private variables in .m file. They are called extensions as well.
For example you have created a variable in your appdelegate file. Now import appdelegate.h file to other .m file. Get the instance of appdelegate by sharedApplication delegate. Now you can set value by below way.
[appdelegate setValue:your_value forKey:#"name of variable"];
Though it was private, user could do so. Its because when you check for auto suggestion window, it will list down your private variable with strike through. To avoid getting those variable inside this window, it is advisable to declare them in .m file.
Why must I define variables twice in the header file? What differences are there between these variables?
The first definition is here:
#interface MyController: UIViewController
{
NSInteger selectedIndex;
}
The second definition is here:
#property (nonatomic) NSInteger selectedIndex;
What you're seeing was required in earlier versions of Objective-C,
but isn't any more.
In the first versions of Objective-C used by NeXT up until the new
runtime was introduced (with Objective-C 2.0 on Mac OS X), all
instance variables had to be declared as part of the class's structure
in its #interface. The reason was that if you subclassed a class,
the compiler needed to know the instance variable layout of the class
so it could see at what offset to put the subclass's instance
variables.
When properties were introduced, synthesized properties had to be
"backed" by an instance variable in the class's structure. Therefore
you had to declare both an instance variable and the property.
All of the above is no longer true. Newer Objective-C is less fragile
in the way it looks up instance variable offsets, which has meant a
few changes:
not all instance variables need to be in the #interface. They can now be defined in the #implementation: though not in categories due
to the possibilities of clashing and other issues.
instance variables for synthesized properties can be inferred and created based on the property definition.
you can programmatically add instance variables to classes you're creating at runtime (only before you've registered the class as
available to the system).
So, to reiterate, you only needed to declare both the instance
variable and a synthesized property in older versions of the
Objective-C language. What you're seeing is redundant and should not
be considered a "best practice".
[Source]
As others have pointed out, it is no longer necessary to declare a backing instance variable for a synthesized property in the header.
To make this a bit clearer though: What you're seeing are not two declarations of the same variable, it is one declaration of the variable and one declaration of the property.
A property is basically a set of methods (in this case selectedIndex and setSelectedIndex:) that are typically used to access instance variables. There is a difference between a property and an instance variable. The property's setter/getter could do more than just set the variable, in your example, it could also e.g. update the UI to reflect the change of the selected index or the getter could infer the index from some other variable (in this case, there might be a selection index path), etc.
Synthesizing a property simply frees you of implementing those methods yourself and provides you with default implementations that simply set the variable, but you could also implement selectedIndex and setSelectedIndex: yourself just like any other method in which case you might either need the instance variable itself or omit it altogether (in case of an inferred property).
In modern runtime you do NOT need to declare them twice. Just use:
In you .h
#property (nonatomic) NSInteger selectedIndex;
The part between the {} is the declaration of the iVar. And with your #property you declare getter and setters. In modern runtime if you just use the code above you say basicly the same (your iVar is now _selectedIndex).
I have a balloonGameViewController.h and another class I made called balloon.h
I want to access some variables I set in balloon.h from the viewController
Is there any way I can achieve this?
How are your variables set in ballon.h? You should use #property to declare variables that you want other classes to be able to access. Then, you can access them either by treating them as a method, or dot notation:
myObject.variable;
myObject should be an instance of type balloon, which can be created by importing the balloon.h and initializing a new instance, if you do not already have one.
Just import the balloon.h file into your balloonGameViewController
#import balloon.h
and then access the variables as usual, assuming they are public. Otherwise you have to make them public or create getters and setters.
As others said, you'll have to #import baloon.h. But you did not say if these variables are global variables or ivars of a class. If they are ivars, you'll first have to find the instance of the class (the object) of which they are ivars. If you have that, and they are public or properties, you can access them as members of that object.
IOW, it is hard to tell if you don't tell us what kind of variables in balloon.h you want to access. But, see above.
i don't know if i got your question well, but i faced that once upon a time , i couldn't access the variables via (.) operator but via (->)
in my case there were 2 classes : MenuCalss , and ToolsClass ;
in ToolsClass.h :
#public
bool ToolBarVisible;
//in MenuCalss there was a ToolsClassObject.
ToolsClassObject is an instance of type ToolsClass, which can be created by importing the ToolsClass.h and initializing a new instance.
, and the access way
in MenuClass.m is :
ToolsClassObject->ToolBarVisible = false;
Using your XCode you need to make import, declare the property, and then use "object.variable" syntax. The file "balloonGameViewController.m" would look in the following way:
#import balloonGameViewController.h
#import balloon.h;
#interface balloonGameViewController ()
...
#property (nonatomic, strong) balloon *objectBalloon;
...
#end
#implementation balloonGameViewController
//accessing the variable from balloon.h
...objectBalloon.variableFromBalloon...;
...
#end