Can anyone please clarify me that where exactly the variables stored in objective c ?
In .h file
#interface example: NSObject
{
NString *string; // where is this stored
int number; // where is this stored
}
#property (nonatomic,strong) NSURL* mURL; // where is this stored
#end
similarly,
In .m file
# import "xyz.h"
NSString *constant = #"hello"; // where is this stored
#interface example()
{
NString *textg; // where is this stored
int numb; // where is this stored
}
#property (nonatomic,strong) NSURL* sURL; // where is this stored
#end
"string", "textg", "number" and "numb" are instance variables to the class. The difference is that "string" and "number" are eligible to be publicly accessible (via ref->number), and "textg" and "numb" are private (since other classes conventionally do not #import .m files).
"mURL" and "sURL" properties are stored as instance variables "_mURL" and "_sURL". Again, "_mURL" is eligible to be publicly accessible (via ref->_mURL), and "_sURL" is not for the same reason.
And, "constant" is an ordinary global variable stored on the heap.
You ask:
where exactly the variables stored
To answer just this: all the variables other than constant, and the variables used by the properties, are stored as part of the memory allocation for each instance of your class example that you create. Every instance has its own copy of each variable. E.g. when you do:
example *anExample = [example new];
You are requesting that an instance of example is created and a reference to it is stored in anExample. That instance contains the all the instance variables and properties you have declared (and it also contains any instance variables and properties for its superclasses, in this just just NSObject).
Your other variable, constant, is declared at the file level. Such variables are stored along with the compiled code in your file as part of your application. Regardless of how many instances of your class are created there is only ever one constant variable. Methods running on behalf of any instance all see the same constant variable.
HTH
Related
I've been writing Objective-C for a few years now, and decided to go back and learn the very basics to help me write even better code. I'm trying to learn all about instance variables, inheritance and class extensions. I've been reading up on all three, but there is one thing that boggles my mind. I have a simple app that contains 2 classes, Person, Male (inherits from Person), and of course Main (which imports the Male class, therefore being able to access the instance variables found in both Person and Male).
The code is simple, and for the sake of space I won't post all of it. Basically Main takes these variables and plays around with them. This is the part that is boggling my mind:
#interface Person : NSObject {
float heightInMeters;
int weightInKilos;
}
#property float heightInMeters;
#property int weightInKilos;
#end
When I delete the brackets and variable declarations, leaving it like this:
#interface Person : NSObject
#property float heightInMeters;
#property int weightInKilos;
#end
The code still inherits and executes just fine.
1. What is the point of even declaring them there in the first place if we can just create two properties?
2. why create two instance variables AND properties to correspond with them?
3. I know that we can declare the variables in the .m instead to keep them private to the class and everything that subclasses it. like this:
#implementation Person {
float heightInMeters;
int weightInKilos;
}
What is the difference here? I feel like I'm missing a lot of basics. Is there a simplistic way of putting this all in perspective?
When you declare a #property, the compiler will automatically synthesize the variable prefixed with an underscore, a getter method, and a setter method.
#interface MyClass ()
#property(strong, nonatomic) NSString *myString;
#end
In this example the compiler would syhtnesize the variable as _myString, the getter as
-(NSString *)myString
and the setter as
-(void)setMyString:(NSString *)string
The keywords after "#property" (strong, nonatomic) define the property's attributes. strong, the default, implies ownership, meaning that in this case MyClass instances will essentially be responsible for the retain/release of their respective myString objects. nonatomic means the variable is not guaranteed to always be a valid value in a multithreaded environment, for example if the getter is called at the same time as the setter.
Additionally, the compiler will treat dot syntax used to retrieve/set instance variables as calls to the appropriate getter/setter methods. Therefore, given an instance of MyClass
MyClass *exampleClass = [[MyClass alloc] init];
Both of the following are equivalent statements:
NSString *string1 = example.myString; // dot syntax
NSString *string1 = [example myString]; // explicit call to the getter method
For further reading, take a look at Apple's Programming with Objective-C Guide.
As for your specific questions:
1. What is the point of even declaring them there in the first place if we can just create two properties?
It's actually not a good idea to declare variables explicitly as public variables in your MyClass.h file (or in most other cases). Instead, declaring them as properties automatically creates a private variable (and accessor methods), making adhering to OOP best practices a little easier. So there is no point in declaring
// MyClass.h
#interface MyClass : NSObject {
NSString *myString // public variables not good
}
Also because of what I stated above regarding dot syntax, if you use self.myString internally in MyClass.m or instanceOfMyClass.myString externally, the public variable myString will never even be touched because the synthesized variable is named _myString.
2. Why create two instance variables AND properties to correspond with them?
See above--you don't need two instance variables, only one.
3. I know that we can declare the variables in the .m instead to keep them private to the class and everything that subclasses it. What is the difference here? I feel like I'm missing a lot of basics. Is there a simplistic way of putting this all in perspective?
If you declare your variables privately in the #implementation part of your .m file, the compiler won't be able to help you by synthesizing the getters and setters. Even as private methods, getters and setters can help reduce complexity in your code, for example checking for the validity of variable values. (Note: you can override accessor methods.)
// MyClass.m
#interface MyClass () // private interface
#property(nonatomic, strong) NSString *myString;
#end
#implementation MyClass {
// no more need for private variables!
// compiler will synthesize NSString *_myString and accessors
}
-(void)setMyString:(NSString *)string { // overwrite setter
// no empty strings allowed in our object (for the sake of example)
NSAssert([string length] > 0, #"String must not be empty");
// assign private instance variable in setter
_myString = string;
}
#end
This way, even when you subclass MyClass, the subclass will inherit the getter and setter methods that were synthesized for us by the compiler.
I'm a debutant to objective-c and I don't understand something.
I practiced c++ so some practices are not instinctif ..
1)
#implementation Car {
// Private instance variables
double _odometer;
}
Why a private attribute is in the .m file ?
2)
#interface Car : NSObject {
// Protected instance variables (not recommended)
}
#property (copy) NSString *model;
-(void)drive
a)It seems model is declared like an attribute, but why it's not recommended to do it in the #interface ?
b) why the drive method is not in the interface ?
3)
What if i'm not use function allocation for exemple for a NString and initialise it directly with #"..." ?
4)
I don't understand the difference between + and - before method declaration too..
Thanks in advance
1.>Why a private attribute is in the .m file
Why not? Everything that is declared inside *.m is private because *.m file could not be imported (included) somewhere. In objective C you can declare instance variables in both files - *.h and *.m
2.a Recommended way is to use accessors (#properties in Objective C). For each property setter, getter and instance variable are generated. Default names for
#property (copy)NSString *str;
are:
- (void)setStr:(NSString*)obj; // setter
- (NSString*)str; //getter
NSString *_str; //instance variable
You can modify accessors names
#property (copy, setter = NewSetterName, getter = NewGetterName )NSString *str;
and instance variable name (should be done #implementation section)
#synthesize str = _newStingInstanceVariable;
Ofcource you can rewrite setters and getters that are generated by default.
2.b Interface is everything between #implementation and #end. {} area after #interface - is a place were you can declare instance variables.
3.It is ok for NSStrings
NSString *str = #"some text";
but for most classes it will not work as you expect:
NSMutableString *str = #"some text";
// You will receive warning here! And str will be NSString, not NSMutableString
4."+" - class methods (static in C++), "-" - instance methods.
There's a general principle in programming that you should make the smallest possible amount of information available to the outside. Anything that's in the .h file, anyone in the world can see, access, and mess up. If there's something wrong with an _odometer and it is in the header file, you have to go through all of your source code to find if something is using it wrong. If it's only in the .m file, you know that if there's a problem, it is in the .m file.
The other reason to not make things public is that you are free to change them if nobody knows about them. For some reason, you decide next month that having _odometer wasn't a good idea in the first place. By now three programmers have changed a dozen files to use _odometer because it was there. So removing that _odometer is now a lot, lot of work. If it was never in the .h file, nobody is using it so you only need to change your own .m file.
I declared an instance variable (not static), just a regular variable in the #implementation section. When I accessed that variable from several objects it appeared that all the objects were sharing the same variable, as if I had declared it static!
I then changed the instance variable to a (strong) property (defined in the .m file to make it private) and it started working as expected, with each object getting their own separate version of the property.
What was going on with that weird "sharing" behavior?
You didn't declare an instance variable. You defined a global variable. You did this:
#implementation MyObject
int myVariable;
but you should have done this:
#implementation MyObject {
int myVariable;
}
When you define a regular var in the #implementation, you define a global variable. For example, in a.m, you define:
#implementation classA
int tryMe = 99;
Then in b.m, you use also use tryMe:
#implementation classB
-(void) func {
extern int tryMe;
NSLog(#"%i", tryMe); // This will print 99.
}
But if you use "static" in a.m, then you will get build error, you will be told that "tryMe" could not be found. Because "static" make the variable local to the file which defines the var.
While, if you define a var as property, then the var is a member of the class, so each instance of the class has its own copy of the var.
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 :-)
Example:
typedef void(^responseBlock)(NSDictionary*, NSError *);
#interface MyClass : NSObject
{
[??] responseBlock responseHandler;
}
What qualifier should I put in the [??] brackets?
I've read that blocks as properties should be setup with the copy qualifier...but in this case I don't need the block exposed as a property. I simply want it to remain an ivar but how can I specify copy? And also, without specifying anything what is the default qualifier used? Is it __strong as in the case with everything else?
I'm using ARC on ios5.
Yes, Blocks are objects in ObjC, so __strong is the appropriate qualifier. Since that's the default, you can in fact leave it off.
There's no way for you to specify that the Block be copied on assignment without a property -- that will be your responsibility (responseHandler = [someBlock copy];). You could declare a property that's only visible to this class itself (not available to other code) by putting a class extension in your .m file:
#interface MyClass ()
#property (copy) responseBlock responseHandler;
#end
This (upon being synthesized) will give you the usual accessor methods, which will take care of the copy for you when you use them.
Also be aware that it's possible (and now the recommended procedure) to declare instance variables in the #implementation block. It sounds like you want this to be a private attribute (no property access), and the ivars declared there can't be seen by any other code. (Of course you don't need to do this if you're using a property; #synthesize will create the ivar for you.)
#implementation MyClass
{
responseBlock responseHandler;
}
// Continue with implementation as usual