Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS Build a Simple iPhone App (iOS7) Refactoring into a Model Readonly Attribute

Nuri Amari
Nuri Amari
8,212 Points

The Predictions Getter & _Predictions Instance Variable

I am currently following these tutorials in order to make a Crystal Ball app. All of my code runs fine, and I have achieved the same result as shown in the tutorials but have had to use slightly different, what I think to be less efficient code. I am also confused about the use of the _predictions property.

Firstly, when I run what I believe is the same code as in the tutorial, as soon as a press the button, the text in the label disappears. If I try to trace out the string that would be displayed by the label I get null. I think this is because the properties getter method, which assigns the array to all of the possible predictions, is never called. To fix this, I called the method in my buttonPressed method. However, in the tutorial this isn't done. What am I missing? All of my code is pasted at the bottom.

Secondly, in the properties getter method name properties, _properties is used often. It is mentioned in the tutorial that this is a instance variable or something similar. What is this property and why doesn't it have to be declared somewhere? Is the underscore of some significance? Once again the code is below.

Any help would be greatly appreciated. Thank you in advance.

NaViewController.h:

#import <UIKit/UIKit.h>

@class NACrystalBall;

@interface NAViewController : UIViewController

@property (strong, nonatomic) IBOutlet UILabel *predictionLabel;

@property (strong, nonatomic) NACrystalBall *crystallBall;

- (IBAction)buttonPressed;

@end

NaViewController.m:

#import "NAViewController.h"
#import "NACrystalBall.h"

@interface NAViewController ()

@end

@implementation NAViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.crystallBall = [[NACrystalBall alloc]init];

    [self.crystallBall predictions];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)buttonPressed {

    self.predictionLabel.text = [self.crystallBall randomPrediction];

}
@end

NaCrystalBall.h:

#import <Foundation/Foundation.h>

@interface NACrystalBall : NSObject

@property (strong, nonatomic) NSArray *predictions;

@property (strong, nonatomic) NSArray *colors;

-(NSString*) randomPrediction;

@end

NaCrystalBall.m:

#import "NACrystalBall.h"

@implementation NACrystalBall

- (void) _predictions {

    if (_predictions == nil) {

        _predictions = [[NSArray alloc] initWithObjects:@"It is certain", @"It is decidedly so", @"All signs say yes", @"The stars are not aligned", @"My reply is no", @"It is doubtful", @"Better not tell you now", @"Concentrate and ask again", @"I am unable to anwer now", nil];

        NSLog(@"YEAH");
    }

}

-(NSString*) randomPrediction {

    [self _predictions];

    int random = arc4random_uniform(self.predictions.count);

    NSLog(@"%@", self.predictions[random]);

    return self.predictions[random];
}

@end

2 Answers

Stefan Malacu
Stefan Malacu
1,428 Points

Hi Nuri,

I ran your code and it works fine :) not really sure what's the issue, but there are some things to be cleared. An instance variable is declared in the .m file like:

@implementation NACrystalBall { NSArray *_ivar; }

then if you want to use it in that class, an operation would look like _ivar.count

An instance variable, or ivar, is not accessible like that from other classes, so you must manually define a getter and setter.

@property does all of this automatically, so you just declare that in the .h file, and this means the _ivar is declared, and also the getter and setter. Like a package, @property includes (_property instance variable, getter method, setter method, and a bunch of other things I don't know of yet). This also means there is more overhead in the performance of an app, but it's insignificant for now

With @property, as example you can set it like this: self.property = value and it's the same thing as calling the method [self setProperty:value] or setting it from outside the class by typing the containing class's name instead of self. You can also override the getter/setter methods by writing your own implementations in the .m file like so - (type *) property { your code here } (for the getter)

What you did there with (void) _predictions is not good practice I believe, methods should not have underscores in order to avoid confusion. Plus, it's an entirely new method, so calling [self _predictions] (custom method which could've been named in any way) is not the same as [self predictions] (the default getter method implied by the @property directive)

Hope I was clear and helpful

Nuri Amari
Nuri Amari
8,212 Points

Thanks, I think that cleared some things up : )