Henry F
Henry F

Reputation: 4980

Simple Class Extension / Inheritance Clarification

I've been writing Objective-C for a few years now, and decided to go back and learn the very basics to help me write even better code. I'm trying to learn all about instance variables, inheritance and class extensions. I've been reading up on all three, but there is one thing that boggles my mind. I have a simple app that contains 2 classes, Person, Male (inherits from Person), and of course Main (which imports the Male class, therefore being able to access the instance variables found in both Person and Male).

The code is simple, and for the sake of space I won't post all of it. Basically Main takes these variables and plays around with them. This is the part that is boggling my mind:

    @interface Person : NSObject {
    float heightInMeters;
    int weightInKilos;
}

@property float heightInMeters;
@property int weightInKilos;

@end

When I delete the brackets and variable declarations, leaving it like this:

@interface Person : NSObject

@property float heightInMeters;
@property int weightInKilos;

@end

The code still inherits and executes just fine.

1. What is the point of even declaring them there in the first place if we can just create two properties?

2. why create two instance variables AND properties to correspond with them?

3. I know that we can declare the variables in the .m instead to keep them private to the class and everything that subclasses it. like this:

    @implementation Person {
    float heightInMeters;
    int weightInKilos;
    }

What is the difference here? I feel like I'm missing a lot of basics. Is there a simplistic way of putting this all in perspective?

Upvotes: 0

Views: 185

Answers (1)

Morgan Chen
Morgan Chen

Reputation: 1217

When you declare a @property, the compiler will automatically synthesize the variable prefixed with an underscore, a getter method, and a setter method.

@interface MyClass () 

@property(strong, nonatomic) NSString *myString;

@end

In this example the compiler would syhtnesize the variable as _myString, the getter as

-(NSString *)myString

and the setter as

-(void)setMyString:(NSString *)string

The keywords after "@property" (strong, nonatomic) define the property's attributes. strong, the default, implies ownership, meaning that in this case MyClass instances will essentially be responsible for the retain/release of their respective myString objects. nonatomic means the variable is not guaranteed to always be a valid value in a multithreaded environment, for example if the getter is called at the same time as the setter.

Additionally, the compiler will treat dot syntax used to retrieve/set instance variables as calls to the appropriate getter/setter methods. Therefore, given an instance of MyClass

MyClass *exampleClass = [[MyClass alloc] init];

Both of the following are equivalent statements:

NSString *string1 = example.myString;   // dot syntax
NSString *string1 = [example myString]; // explicit call to the getter method

For further reading, take a look at Apple's Programming with Objective-C Guide.

As for your specific questions:

1. What is the point of even declaring them there in the first place if we can just create two properties?

It's actually not a good idea to declare variables explicitly as public variables in your MyClass.h file (or in most other cases). Instead, declaring them as properties automatically creates a private variable (and accessor methods), making adhering to OOP best practices a little easier. So there is no point in declaring

// MyClass.h

@interface MyClass : NSObject {
    NSString *myString // public variables not good
}

Also because of what I stated above regarding dot syntax, if you use self.myString internally in MyClass.m or instanceOfMyClass.myString externally, the public variable myString will never even be touched because the synthesized variable is named _myString.

2. Why create two instance variables AND properties to correspond with them?

See above--you don't need two instance variables, only one.

3. I know that we can declare the variables in the .m instead to keep them private to the class and everything that subclasses it. What is the difference here? I feel like I'm missing a lot of basics. Is there a simplistic way of putting this all in perspective?

If you declare your variables privately in the @implementation part of your .m file, the compiler won't be able to help you by synthesizing the getters and setters. Even as private methods, getters and setters can help reduce complexity in your code, for example checking for the validity of variable values. (Note: you can override accessor methods.)

// MyClass.m

@interface MyClass () // private interface

@property(nonatomic, strong) NSString *myString;

@end


@implementation MyClass {
    // no more need for private variables!
    // compiler will synthesize NSString *_myString and accessors
}

-(void)setMyString:(NSString *)string { // overwrite setter

    // no empty strings allowed in our object (for the sake of example)
    NSAssert([string length] > 0, @"String must not be empty");

    // assign private instance variable in setter
    _myString = string;
}

@end

This way, even when you subclass MyClass, the subclass will inherit the getter and setter methods that were synthesized for us by the compiler.

Upvotes: 2

Related Questions