0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Define Variables and Methods of Class in Objective-C

Posted at

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

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 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

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:

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

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.
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?