Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this a new way to define private instance variables in Objective-C?

Tags:

objective-c

I've recently updated to Xcode 4.3.2 and found that I can now declare private instance variables inside @implementation block like so:

@interface TestClass : NSObject
@property (nonatomic, copy) NSString *testProp;
@end

@implementation TestClass {
    NSString *_testPropStore;
}

- (NSString *)testProp { return _testPropStore; }
- (void)setTestProp:(NSString *)testProp { _testPropStore = [testProp copy]; }

- (id)init {
    if (self = [super init]) {
        _testPropStore = nil;
    }
    return self;
}

@end

Notice the NSString *_testPropStore line inside @implementation brace block.

I've also tested with the following code:

TestClass *c1 = [[TestClass alloc] init];
TestClass *c2 = [[TestClass alloc] init];

c1.testProp = @"Hello";
c2.testProp = @"World";

NSAssert(c1.testProp == c2.testProp, @"It's working!");

Which seems to work fine. (That is, the app crashes with the "It's working" message at the NSAssert line.)

So is this a new feature of Objective-C for declaring private instance variables? Since I discovered this by accident, I would love to know if it is just for declaring private instance variables or will there be any side effects that I'm not aware of?

I couldn't find any relevant document since most questions of such type with the word private just ended up with answers on how to declare them on a private extension category which is different.

like image 366
chakrit Avatar asked May 02 '12 04:05

chakrit


People also ask

Can you make instance variables private?

Instance variables are encapsulated by using the private access modifier. Methods can be public or private, but they are usually public.

How do you declare an instance variable in Objective-C?

In Objective-C, instance variables are commonly created with @propertys. An @property is basically an instance variable with a few extra bonus features attached. The biggest addition is that Objective-C will automatically define what's called a setter and a getter for you automatically.

Should instance variables be declared private?

The instance variables are visible for all methods, constructors, and block in the class. Normally, it is recommended to make these variables private (access level). However, visibility for subclasses can be given for these variables with the use of access modifiers. Instance variables have default values.


1 Answers

It's for real, it's the new way,* it's great, and, yes, it's in the docs. The Objective-C Programming Language, which is as close as we get to having an actual spec for the language, has the following to say:

The definition of a class is structured very much like its declaration. It begins with an @implementation directive and ends with the @end directive. In addition, the class may declare instance variables in braces after the @implementation directive:

@implementation ClassName
{
    // Instance variable declarations.
}
// Method definitions.
@end

There's also a historical note a little ways back from that link, addressing the fact that we used to have to declare ivars in the interface block:

Historically, the interface required declarations of a class’s instance variables, the data structures that are part of each instance of the class. ... Instance variables represent an implementation detail, and should typically not be accessed outside of the class itself. Moreover, you can declare them in the implementation block or synthesize them using declared properties. Typically you should not, therefore, declare instance variables in the public interface and so you should omit the braces.

For the question of privacy, yes, these variables are truly private -- they act like ivars declared in the interface with the @private directive. This means that subclasses can't access them, by default. Their visibility can be changed, however, using either @protected or (if necessary for some bizarre reason) @public:

@interface Stuper : NSObject 
@end

@implementation Stuper
{
    @protected
    NSString * sangfroid;
}
@end

@interface Stub : Stuper
- (void)setSangfroid: (NSString *)newSangfroid;
@end

@implementation Stub

- (void)setSangfroid: (NSString *)newSangfroid {
    sangfroid = [newSangfroid copy];
}

*You have to use clang > 3.0, I believe, so that's just a few months ago as of this posting. GCC won't do it.

like image 77
jscs Avatar answered Oct 16 '22 01:10

jscs