Objective-C instance variables?

Objective C

Objective C Problem Overview


I'm sure my confusion here is just a result of being stuck in a "Java mindset" and not understanding how Obj-C differs in this case.

In Java, I can declare a variable in a class, like this, and each instance of that class will have it's 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 like this:

#import "MyClass.h"

@implementation MyClass

NSString *testVar;

@end

My expectation here was that this variable has a scope limited to this class. So I created a second class (identical):

#import "MySecondClass.h"

@implementation MySecondClass

NSString *testVar;

@end

What I'm seeing (and has me baffled) is that changing the variable in one class, affects the value seen in the other class. In fact, if I set a breakpoint, and then "Jump to Definition" of the variable, it takes me to th

I've created an extremely small Xcode project that demonstrates the problem here.

Objective C Solutions


Solution 1 - Objective C

Change this:

@implementation MyClass

NSString *testVar;

@end

to:

@implementation MyClass {
    NSString *testVar;
}

// methods go here

@end

and you'll get what you expected.

As you had it, you are actually creating a global variable. The two global variables were combined into one by the linker which is why both changed when you set one. The variable in curly braces will be a proper (and private) instance variable.

Edit: After being downvoted for no apparent reason, I thought I'd point out the "old" way of doing things, and the new way.

The 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 the new and improved way with 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 way has several advantages. The primary advantage is that none of the implementation specific details about the class appear in the .h file. A client has no need to know what delegates the implementation needs. The client has no need to know what ivars I use. Now, if the implementation needs a new ivar or it needs to use a new protocol, the .h file doesn't change. This mean less code gets recompiled. It cleaner and much more efficient. It also makes for easier editing. When I'm editing the .m file and realize I need a new ivar, make the change in the same .m file I'm already editing. No need to swap back and forth.

Also note the implementation no longer needs an ivar or @synthesize for the property.

Solution 2 - Objective C

What you probably want (unless you're using a very old OS and compiler) is to just use 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 an instance variable and a getter/setter pair for this variable. If you manually wanted to create the instance variable (you generally don't need that unless you need your code to work on very old MacOS versions), this is what the above code does under the hood to create the ivar:

@interface MyClass : NSObject
{
    NSString*    _myVar;
}

// method declarations here.

@end

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

If you are creating the property only for internal use and don't want clients of your class to mess with it, you can hide this away a little bit in everything but the oldest ObjC compilers by using a class extension which "continues" the class declaration from the header, but can be placed separate from it (so usually in your implementation file). A class extension looks like a category without a name:

@interface MyClass ()

@property (copy) NSString*    myVar;

@end

And you can either put your property declaration in there, or even ivar declarations (again wrapped in curly brackets). You can even declare the same property as readonly in the class interface, and then re-declare it identical, but as readwrite in the extension, so that clients only read it, but your code can change it.

Note that, if you didn't use ARC (that is, you've switched off the default of Automatic Reference Counting), you would have to set all your properties to nil in your dealloc method (unless they're set to weak or assign of course).

NB - All the above are @interface sections. Your actual code will go in separate @implementation sections. This is so you can have header files (.h) you can hand off to your class's clients that just contain the portions you intend them to use, and hide away implementation details in the implementation file (.m) where you can change them without having to worry someone might have accidentally used them and you'll break other code.

PS - Note that NSStrings and other objects that you want the immutable flavor of, but that also exist in a mutable flavor (i.e. NSMutableString) should always be copy properties, because that will turn an NSMutableString into an NSString so that nobody on the outside can change the mutable string underneath you. For all other object types, you generally use strong (or retain if not ARC). For your class's owner (e.g. its delegate) you usually use weak (or assign if not ARC).

Solution 3 - Objective C

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

Solution 4 - Objective C

In objective-c, you define the variable as private by doing like so

MyClass.h

@interface MyClass : NSObject{

      NSString* _myTestVar; // Declaration
}
@end

and refer to it in the implementation class by doing like so MyClass.m

#import "MyClass.h";

@implementation MyClass

  -(void)initializieTheString
  {
     _myTestVar= @"foo"; //Initialization
     
  }

@end

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDwayne KingView Question on Stackoverflow
Solution 1 - Objective CrmaddyView Answer on Stackoverflow
Solution 2 - Objective CuliwitnessView Answer on Stackoverflow
Solution 3 - Objective CGangcilView Answer on Stackoverflow
Solution 4 - Objective CEdwin O.View Answer on Stackoverflow