Objective-C instance variables?

I'm sure my confusion here is the result of being stuck in “Java thinking” and not understanding how Obj-C is different in this case.

In Java, I can declare a variable in a class, like this, and each instance of this class will have its own:

MyClass { String myVar; MyClass() { // constructor } } 

In Obj-C, I tried to do the same thing by declaring a variable only in the .m file as follows:

 #import "MyClass.h" @implementation MyClass NSString *testVar; @end 

I expected this variable to have a scope limited to this class. So I created a second class (identical):

 #import "MySecondClass.h" @implementation MySecondClass NSString *testVar; @end 

What I see (and am confusing) is that changing a variable in one class affects the value visible in another class. In fact, if I set a breakpoint and then the "Go to definition" variable, it will lead me to

I created a very small Xcode project that demonstrates the problem here .

+48
objective-c
Nov 07
source share
4 answers

Change this:

 @implementation MyClass NSString *testVar; @end 

at

 @implementation MyClass { NSString *testVar; } // methods go here @end 

and you get what you expected.

As you did, you are actually creating a global variable. Two global variables were combined into one linker, so both changed when it was set. The variable in braces will be the correct (and private) instance variable.

Edit: after I was nobody for no apparent reason, I thought that I would point to the “old” way of doing things and the new way.

Old way:

SomeClass.h

 @interface SomeClass : UIViewController <UITextFieldDelegate> { UITextField *_textField; BOOL _someBool; } @property (nonatomic, assign) BOOL someBool; // a few method declarations @end 

SomeClass.m

 @implementation SomeClass @synthesize someBool = _someBool; // the method implementations @end 

Now a new and improved way using the modern Objective-C compiler:

SomeClass.h

 @interface SomeClass : UIViewController @property (nonatomic, assign) BOOL someBool; // a few method declarations @end 

SomeClass.m

 @interface SomeClass () <UITextFieldDelegate> @end @implementation SomeClass { UITextField *_textField; } // the method implementations @end 

The new method has several advantages. The main advantage is that none of the specific information about this class appears in the .h file. The client does not need to know which delegates need to be implemented. The client does not need to know which berries I use. Now, if the implementation needs a new ivar or it needs a new protocol, the .h file does not change. This means that less code is recompiled. It is cleaner and much more efficient. It also simplifies editing. When I edit the .m file and understand that I need a new ivar, make changes to the same .m file that I am already editing. No need to change back and forth.

Also note that implementation no longer requires ivar or @synthesize for the property.

+127
Nov 07
source share

In java

 MyClass { String myVar; MyClass() { // constructor } } 

In Objective-c

 MyClass.h @interface MyClass : NSObject{ NSString* str; // Declaration } @end MyClass.m @implementation MyClass -(void)initializieTheString { //Defination } @end 
+1
Nov 07 '12 at 9:11
source share

What you probably want (if you are not using a very old OS and compiler), just use the property syntax. I.e:.

 @interface MyClass : NSObject // method declarations here ... @property (copy) NSString* myVar; // ... or here. @end 

This will do what you intended to do. This will implicitly synthesize the instance variable and the getter / setter pair for this variable. If you manually wanted to create an instance variable (you don't need it at all if you don't need your code to work on very old versions of MacOS), this is what the above code does under the hood to create ivar:

 @interface MyClass : NSObject { NSString* _myVar; } // method declarations here. @end 

Note the braces that tell the compiler that this is not just a global variable somewhere between methods, but actually an instance variable belonging to this object.

If you create a property for internal use only and don’t want the clients of your class to ruin it, you can hide it a bit in everything except the oldest ObjC compilers, using a class extension that “continues” the class declaration from the header, but may be allocated separately from it (usually this is in your implementation file). The class extension looks like a category without a name:

 @interface MyClass () @property (copy) NSString* myVar; @end 

And you can either place a property ad, or even ivar ads (wrapped in braces again). You can even declare the same property as readonly in the class interface, and then re-declare it identical, but like readwrite in the extension so that clients only read it, but your code can change it.

Note that if you did not use ARC (that is, you turned off the default for automatic reference counting), you would need to set all your properties to nil in your dealloc method (except they are set to weak or assign , of course).

NB - all of the above @interface sections. Your actual code will go into separate sections of @implementation . Thus, you can have header files ( .h ) that you can transfer to your class clients that contain only those parts that you intend to use, and hide implementation details in the implementation file ( .m ), where you can change them without worrying that someone accidentally used them, and you break another code.

PS - Please note that NSStrings and other objects that you want to have an unchanging taste, but which also exist in a mutable taste (i.e. NSMutableString ), should always be copy properties, because this will turn NSMutableString into NSString so that no one externally could change the mutable string below you. For all other types of objects, you usually use strong (or retain , if not ARC). For your class owner (e.g. its delegate), you usually use weak (or assign , if not ARC).

+1
May 09 '15 at 9:44
source share

In objective-c, you define a variable as confidential, doing so

 MyClass.h @interface MyClass : NSObject{ NSString* _myTestVar; // Declaration } @end 

and reference it in the implementation class, doing so MyClass.m

 #import "MyClass.h"; @implementation MyClass -(void)initializieTheString { _myTestVar= @"foo"; //Initialization } @end 
0
May 09 '15 at 8:18
source share



All Articles