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

Mike Gilroy
Mike Gilroy
7,411 Points

Readonly Attributes: 'randomPrediction' bug

After creating the custom CrystalBall class and following the video for what code to put where, I'm struggling to find the reason for the following error.

For the following piece of code I am getting an error that reads:

"No visible @interface for 'MGViewController' declares the selector 'randomPrediction'"

Here's the code with the error:

- (IBAction)buttonPressed {

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

}

Also when typing out 'randomPrediction' above it does not suggest this as an option, which suggest something is not quite right in the first place.

If it helps this is all the code I have used for my app:

MGCrystalBall.h

#import <Foundation/Foundation.h>

@interface MGCrystalBall : NSObject
@property (nonatomic, strong) NSArray *predictions;
@property (nonatomic, strong) NSString *randomPrediction;

- (NSArray*) predictions;
- (NSString*) randomPrediction;

@end

MGCrsytalBall.m

#import "MGCrystalBall.h"

@implementation MGCrystalBall


- (NSArray *) predictions {
    if (_predictions == nil){
        _predictions = [[NSArray alloc] initWithObjects:

        @"YES",
        @"NO",
        @"Maybe",
        @"I can't be certain",
        @"It's a definite",
        @"It is doubtful",
        @"My reply is no",
        @"Unable to answer now",
        nil];
    }

    return _predictions;
}

- (NSString*) randomPrediction {
    int random = arc4random_uniform(self.predictions.count);
    return [self.predictions objectAtIndex:random];
}

@end

MGViewController.h

#import <UIKit/UIKit.h>

@class MGCrystalBall;

@interface MGViewController : UIViewController
@property (strong, nonatomic) IBOutlet UILabel *predictionLabel;
@property (strong, nonatomic) MGViewController *crystalBall;

- (IBAction)buttonPressed;
@end

MGViewController.m

#import "MGViewController.h"
#import "MGCrystalBall.h"

@interface MGViewController ()

@end

@implementation MGViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.crystalBall = [[MGViewController alloc] init];

}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];

}

- (IBAction)buttonPressed {

    self.predictionLabel.text = [self.crystalBall randomPrediction];
//above is the line of code where I am receiving the error
}
@end

Can anyone see where I have gone wrong here? Help would be much appreciated as I have gone back through the videos and can't see how my code differs to that in the videos.

Thanks in advance!

4 Answers

Stone Preston
Stone Preston
42,016 Points

oh. you also need to change a line in your header file as well. sorry I missed that the first time

see the error below. you need to have a MGCrystalBall property.

MGViewController.h

#import <UIKit/UIKit.h>

@class MGCrystalBall;

@interface MGViewController : UIViewController
@property (strong, nonatomic) IBOutlet UILabel *predictionLabel;

//this needs to be a crystal ball, not a MGViewController
@property (strong, nonatomic) MGViewController *crystalBall;

to fix it, just change it to a cyrstal ball object

MGViewController.h

#import <UIKit/UIKit.h>

@class MGCrystalBall;

@interface MGViewController : UIViewController
@property (strong, nonatomic) IBOutlet UILabel *predictionLabel;

//this needs to be a crystal ball, not a MGViewController
@property (strong, nonatomic) MGCrystalBall *crystalBall;
Stone Preston
Stone Preston
42,016 Points

I think I found whats causing the issue. you are allocating your self.crystalBall property as an MGViewController object, not an MGCrystalBall object in your MGViewCOntroller.m file

MGViewController.m

#import "MGViewController.h"
#import "MGCrystalBall.h"

@interface MGViewController ()

@end

@implementation MGViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    //this needs to be a crystal ball object, not a MGViewController
    //see how you allocate it as an MGViewController object when it needs to be MGCrystalBall?
    self.crystalBall = [[MGViewController alloc] init];

}

to fix it just change that line to

- (void)viewDidLoad
{
    [super viewDidLoad];

    //you need to allocate a MGCrystalBall object here. 
    self.crystalBall = [[MGCrystalBall alloc] init];

}
Mike Gilroy
Mike Gilroy
7,411 Points

Hi Stone, thanks for the quick response!

I've done what you've suggested though and this still doesn't get rid of the error, plus I'm now seeing a caution sign next to the new line of code reading "Incompatible pointer types assigning to 'MGViewController *' from 'MGCrystalBall *' "

Any idea what else might be wrong?

Here's the code after changing:

#import "MGViewController.h"
#import "MGCrystalBall.h"

@interface MGViewController ()

@end

@implementation MGViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.crystalBall = [[MGCrystalBall alloc] init];

}

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

- (IBAction)buttonPressed {

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

}
@end
Mike Gilroy
Mike Gilroy
7,411 Points

Thanks Stone, this fixed it! Think I must of just chosen the wrong one from the suggestions when typing out MG...

Cheers! :)

Stone Preston
Stone Preston
42,016 Points

yeah thats probably what happened. Glad you got it fixed