Define Variables and Methods of Class in Objective-C

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



tree.h
#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

tree.m
#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 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:

main.m
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:

tree.m
#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:

tree.h
@interface tree : NSObject

@property (nonatomic, weak) NSString *treeName;

@end

It means you create three things:
1. Define treeName property with nonatomic and weak attributes(It's likely a _treeName protected instance variable).
2. Define a method - (void)setTreeName:(NSString * _Nullable)treeName .
3. 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 fun 't we call another function? And actually you can! But you can only use treeName 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 . or self.property . But it's better to use _property because once you use _property Xcode compiler will call the function. you may get an endless loop while rewriting the getter or setter:

tree.m
@implementation tree {
    BOOL hasSetTreeName;
}

- (void)setTreeName:(NSString *)treeName {
    hasSetTreeName = YES;
    self.treeName = treeName;
}

@end

In this case you may crash because of self.property in function [self property] ;

Variables in Implementation Block



A few years ago(exactly 2013), Objective-C allows developer to define the private instance variable in the implementation

tree.m
@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.
  • 좋은 웹페이지 즐겨찾기