Up to now, the syntax of Objective-C has been changed for many times. If you create a class, you can declare the variables and methods in interface block or implementation block or as properties. But what are the differences among them? This article may help you to distinguish.
Test Environment: Xcode 7.2, OS X 10.11
A Likely More Correct Definition of Class
# import <Foundation/Foundation.h>
typedef NS_ENUM(NSUInteger, TreeSize) {
TreeSizeLow = -1,
TreeSizeNormal = 0,
TreeSizeHigh,
};
@interface tree : NSObject {
@public
TreeSize size;
@protected
NSUInteger high;
NSUInteger girth;
}
@property (nonatomic, weak) NSString *treeName;
@property (nonatomic, weak, readonly) NSString *locale;
- (NSString *)decriptionWithTreeSize:(TreeSize)treeSize;
- (void)growUp;
@end
# import "tree.h"
@implementation tree {
NSString *material;
}
- (instancetype)init {
self = [super init];
if (self) {
_locale= @"solar system";
size = TreeSizeLow;
material = @"iron";
}
return self;
}
- (NSString *)decriptionWithTreeSize:(TreeSize)treeSize {
switch (treeSize) {
case TreeSizeLow:
return @"It's really low.";
case TreeSizeNormal:
return @"Just so so~";
case TreeSizeHigh:
return @"High enough!";
default:
return @"I won't say anything because of error.";
}
}
- (void)growUp {
if ([material isEqualToString:@"iron"]) {
return;
}
high++;
girth++;
}
@end
Variables in Interface Block
Instance variables are defined in interface block. Just like the size
instance variable in tree
class. Normally, if you don't add any prefix such as @public
, it will be seen as public instance variable by Xcode compiler. But notice once you have prefix of instance variable, the following variables will behave under it.(e.g. girth
in tree
class is protected)
To all instance variables, you can just use them with their name directly in functions of class in implementation block.
A public instance variable means you can get this variable from the object of this class, for instance:
int main(int argc, const char *argv[]) {
...
NSLog(@"The tree size number is %lu.", aTree->size);
...
}
But if an instance variable is defined with @protected
or @private
, you can not get the variable outside the class definition or get error.
What's more, Objective-C allows you define the private instance variable in an anonymous category, just like:
# import "tree.h"
@interface tree () {
// you can define instance variable here
}
@implementation tree
...
@end
And the instance variables in this category will be seen as private by Xcode compiler whatever you add a prefix. The advantage is that you can hide the private instance varibles from the header.
In addition, if the class with instance variable has a subclass, the private instance variable can not be used in subclass.
Variables as Properties
You can define a property of class in this way:
@interface tree : NSObject
@property (nonatomic, weak) NSString *treeName;
@end
It means you create three things:
- Define
treeName
property withnonatomic
andweak
attributes(It's likely a_treeName
protected instance variable). - Define a method
- (void)setTreeName:(NSString * _Nullable)treeName
. - Define a method
- (NSString * _Nullable)treeName
.
In the past(exactly before 2012), you must use @synthesize
to enable the property, but now it's no need.
There are two ways to get the treeName
property outside the class, the first one is [aTree treeName]
and the second is aTree.treeName
. You may think that if we can use a dot operator to call function treeName
, why don't we call another function? And actually you can! But you can only use .
operator to call a function which must has no parameter. However Xcode compiler still prompt a warning.
In the implementation of class, you can get the property by using self.property
or _property
. But it's better to use _property
because once you use self.property
Xcode compiler will call the function [self property]
or [self getProperty]
and you may get an endless loop while rewriting the getter or setter:
@implementation tree {
BOOL hasSetTreeName;
}
- (void)setTreeName:(NSString *)treeName {
hasSetTreeName = YES;
self.treeName = treeName;
}
@end
In this case you may crash because of EXC_BAD_ACCESS
in function setTreeName:
;
Variables in Implementation Block
A few years ago(exactly 2013), Objective-C allows developer to define the private instance variable in the implementation
@implementation tree {
// define private instance variable here
}
@end
Also, you can use it directly with name in function of class in implementation block.
In Conclusion
- Define the variables in implementation block if you use them just in this class and do not show to other classes.
- Define the variables in interface block if you have members inherited by subclass.
- Define the variables as property if you want to use directly by other classes.