views:

421

answers:

2

I am not an idiot, but header files make me feel like one sometimes. I have what is probably an overly-complicated set-up that has an error that I cannot resolve. Here it is in about as simple as detail as I can make it....

  • I have a Controller class that contains a Model class.
  • I have a Scene class to capture actions and communicates with the Controller.
  • I have a Layer class that talks with the Model class to output the state of the Model.
  • The Scene class contains Layer class solely for output.
  • Scenes must hold Layers as determined by the Cocos2D framework.
  • Specific Scene classes derive from a RootScene class that holds the reference to the Controller class.
  • Specific Layer classes derive from a RootLayer class that holds the reference to the Model class.
  • The Controller is responsible for creating Scenes and Scenes are responsible for creating Layers.

The problem comes when making a Layer and passing the Controller's Model to the Layer's Model (in AScene.m). I get the "Request for member 'Model' in something not a stucture or union". Casting doesn't work, and I'm at a loss for how to allow these classes to talk with each other. I think part of the problem might be that Controller class contains the Model class.

Controller.h

#import <Foundation/Foundation.h>

@class Model;
@class AScene;

@interface Controller : NSObject {
    Model *Model;
}
@property (nonatomic, retain) Model *Model;
-(void)runScene;

Controller.m

#import "Controller.h"

#import "Model.h"
#import "AScene.h"

@implementation Controller

@synthesize Model;

- (void)runScene {
    AScene *newScene = [[AScene alloc] init];
    newScene.controller = self;
}

RootScene.h

#import "cocos2d.h"

@class Controller;

@interface RootScene : Scene {
    Controller *controller;
}
@property (nonatomic, retain) Controller *controller;

@end

RootScene.m

#import "RootScene.h"
#import "Controller.h"

@implementation RootScene

@synthesize controller;

- (id) init {
    self = [super init];
    if (self != nil) {
     //
    }
    return self;
}

- (void) dealloc {
    [controller release];
    [super dealloc];
}

@end

AScene.h

#import "RootScene.h"

@class ALayer;
@class Model;

@interface AScene : RootScene {
}

@end

AScene.m

#import "AScene.h"
#import "ALayer.h"
#import "Model.h"

@implementation AScene

- (id) init {
    self = [super init];
    if (self != nil) {
     ALayer *newLayer = [ALayer node];
     newLayer.model = controller.Model; // <-- Request for member 'Model' in something not a stucture or union
     [self addChild:statusScreenLayer];
    }
    return self;
}

- (void) dealloc {
    [super dealloc];
}

@end

RootLayer.h

#import "cocos2d.h"

@class Model;

@interface RootLayer : Layer {
    Model *model;
}
@property (nonatomic, retain) Model *model;

@end

RootLayer.m

#import "RootLayer.h"

#import "Model.h"

@implementation RootLayer

@synthesize model;

- (id) init {
    self = [super init];
    if (self != nil) {
     //
    }
    return self;
}

- (void) dealloc {
    [model release];
    [super dealloc];
}

@end

ALayer.h

#import "RootLayer.h"

@interface ALayer : RootLayer {
}
-(void) draw;

@end

ALayer.m

#import "ALayer.h"

@implementation ALayer

-(void) draw {
    // draw based on state of the model
}

@end
+3  A: 

Your implementation of AScene does not #import the header of Controller.

Edit: Explicit solution.

In AScene.m add:

#import "Controller.h"
Nikolai Ruhe
Controller.h is imported in the parent class of AScene: RootScene.
Philip Regan
Classes cannot import anything. Header files are imported by implementation files or other header files. That's what I meant with my answer: The implementation file of AScene ("AScene.m") does not import "Controller.h", neither directly nor indirectly.
Nikolai Ruhe
@Philip, to accomplish what you assumed is happening, you could replace `@class Controller;` in RootScene.h with `#import "Controller.h"`. Generally, it's best practice to minimize imports in headers, but in this case the child class(es) should probably have the same import. Since it's used in both places, just move it from the .m to the .h file.
Quinn Taylor
+1  A: 

Nikolai seems to be right. Beyond that, best practice would dictate that properties (like ivars) should NOT start with an uppercase letter. You're just asking for hurt. Use these instead:

Controller.h

@interface Controller : NSObject {
    Model *model;
}
@property (nonatomic, retain) Model *model;

Controller.m

@synthesize model;
Quinn Taylor
"You're just asking for hurt." In what way? Is it an expectation of the compiler or Objective-C to have lower-case ivars?
Philip Regan
It is an expectation of developers. If you were the only developer to look at your code you could do what you want. But you're not. You share code, so you should use the style that others understand.
Nikolai Ruhe
Correct. It's assumed that leading with a capital letter means a class, struct, etc. and that methods, ivars, and properties start with lowercase. It's actually a trend across most programming languages, so anytime you post code to have someone help you with a problem, they're likely to be immediately confused by the choice. (Also notice how the markdown on this site renders `Model *Model` versus `Model *model`.) In addition, using the identical name and capitalization is even more error prone — in my book, even `Model *MyModel` would be preferable. But then, I have strong opinions. :-)
Quinn Taylor
Thanks for the info. Much appreciated.
Philip Regan