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
```objc: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
```

```objc: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 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:

```objc: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:

```objc: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:

```objc: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 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.
![Screen Shot 2016-04-25 at 11.53.52 AM.png](https://qiita-image-store.s3.amazonaws.com/0/114282/4700d22e-10c3-c8ed-df44-6f317d54ae7a.png)

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:

```objc:tree.m
@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

```objc: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.