0

I have a class that inherits from CCSprite called GameObject. I also have a singleton called ActionDispatcher that inherits from NSObject.

The ActionDispatcher sharedActionDispatcher's job is to return a CCActionInterval when asked, and the method that does this requires a reference to the asking object, which is of type GameObject (or a subclass thereof). But for the GameObject to be able to ask for this, it needs to refer to ActionDispatcher. So I have a #import "GameObject.h" in the ActionDispatcher header and a #import "ActionDispatcher" in the GameObject header.

I get an error: Expected ')' before 'GameObject' in the ActionManager method that takes a reference to a GameObject.

EDIT: added comments to show where I fixed this per the accepted answer below.


//The GameObject interface

#import "cocos2d.h"
#import "ActionDispatcher.h"

@interface GameObject : CCSprite {
    CGPoint homeLocation;
}

@property (readwrite) CGPoint homeLocation;

- (void)updateStateWithDeltaTime:(ccTime)deltaTime 
        andListOfGameObjects:(CCArray*)listOfGameObjects;

@end

//The GameObject implementation

#import "GameObject.h"

@implementation GameObject

@synthesize homeLocation;

- (void)updateStateWithDeltaTime:(ccTime)deltaTime 
        andListOfGameObjects:(CCArray *)listOfGameObjects 
{
    //CCLOG(@"updateStateWithDeltaTime method should be overriden");
}

@end

//The ActionDispatcher interface

#import "cocos2d.h"
#import "CCRotateAround.h"
#import "Constants.h"
#import "GameObject.h" // Answer: Remove this line

// Add this here: @class GameObject;

@interface ActionDispatcher : NSObject {

}

+ (ActionDispatcher *)sharedActionDispatcher;

- (id)actionWithType:(ActionType)actionType 
          withObject:(GameObject *)gameObject 
        withDuration:(float)duration;

@end

//The ActionDispatcher implementation

#import "ActionDispatcher.h"
// and add this here: #import "GameObject.h"

@implementation ActionDispatcher

static ActionDispatcher* _sharedActionDispatcher = nil;

+ (ActionDispatcher*)sharedActionDispatcher 
{
    @synchronized([ActionDispatcher class])                             
    {
        if(!_sharedActionDispatcher)                                    
            [[self alloc] init]; 
        return _sharedActionDispatcher;                                 
    }
    return nil; 
}

+ (id)alloc 
{
    @synchronized ([ActionDispatcher class])                            
    {
        NSAssert(_sharedActionDispatcher == nil,
                 @"Attempted to allocated a second instance of the ActionManager singleton");                                          
        _sharedActionDispatcher = [super alloc];
        return _sharedActionDispatcher;                                 
    }
    return nil;  
}

- (id)actionWithType:(ActionType)actionType 
          withObject:(GameObject *)gameObject 
        withDuration:(float)duration
{
    CGSize screenSize = [[CCDirector sharedDirector] winSize];

    id action = nil;

    switch (actionType) {
        case kActionDiveBomb:
            CCLOG(@"ActionManager returning action of type: dive bomb");
            CGPoint controlPoint1 = ccp(gameObject.position.x, gameObject.position.y*0.5f);
            CGPoint controlPoint2 = ccp(screenSize.width*0.5f, gameObject.position.y*0.5f);
            CGPoint destination = ccp(screenSize.width*0.5f, -gameObject.contentSize.height*0.5f);
            ccBezierConfig diveBombBezier;
            diveBombBezier.controlPoint_1 = controlPoint1;
            diveBombBezier.controlPoint_2 = controlPoint2;
            diveBombBezier.endPosition = destination;
            id diveAction = [CCBezierTo actionWithDuration:duration bezier:diveBombBezier];
            id returnToTopAction = [CCMoveTo actionWithDuration:0.0f position:ccp(gameObject.homeLocation.x, screenSize.height+gameObject.contentSize.height/2)];
            id fallInAction = [CCMoveTo actionWithDuration:duration*0.2 position:gameObject.homeLocation];
            action = [CCSequence actions:diveAction, returnToTopAction, fallInAction, nil];
            break;
        case kActionLoop:
            CCLOG(@"ActionManager returning action of type: loop");
            CGPoint centerPoint = ccp(screenSize.width/2, screenSize.height/2);
            float span = 360.0;
            action = [CCRotateAround actionWithDuration:duration centerPoint:centerPoint spanAngle:span];
            break;
        case kActionSpin:
            CCLOG(@"ActionManager returning action of type: spin");
            action = [CCRotateBy actionWithDuration:duration angle:360.0f];
            break;
        case kActionGoHome:
            CCLOG(@"ActionManager returning action of type: go home");
            action = [CCMoveTo actionWithDuration:0.0f position:[gameObject homeLocation]];
            break;
        case kActionFallIn:
            CCLOG(@"ActionManager returning action of type: fall in");
            action = [CCMoveTo actionWithDuration:duration position:[gameObject homeLocation]];
            break;
        case kActionIdle:
            CCLOG(@"ActionManager returning action of type: idle");
            action = [CCDelayTime actionWithDuration:duration];
            break;
        default:
            CCLOG(@"ActionManager returning action of type: no valid action");
            break;
    }

    return action;
}

@end
CodeSmile
  • 64,284
  • 20
  • 132
  • 217
Steve
  • 6,332
  • 11
  • 41
  • 53

3 Answers3

2

Just add a @class directive in ActionDispatcher.h above the @interface. This is a forward declaration of a class that is imported in the implementation.

@class GameObject;

Mark Adams
  • 30,776
  • 11
  • 77
  • 77
0

Possible. Try inserting

@class GameObject

forward declaration after the import in ActionManager.m? This should break the cycle.

futureelite7
  • 11,462
  • 10
  • 53
  • 87
-1

This is not the problem. #import directive automatically handles inclusion of already included files. Discussion is here. To check it comment out all other imports, subclass your GameObject from NSObject and it will compile without errors. The error tells you there is something wrong in one of the files you include. Sometimes it can be a wrong symbol in a header file after the @end keyword, which makes the compiler complain in the wrong place.

Community
  • 1
  • 1
Davyd Geyl
  • 4,578
  • 1
  • 28
  • 35
  • This is a common misunderstanding. `#import` prevents files from being included multiple times, but that doesn't do anything for circular dependencies. If File A needs the contents of File B to go before it, and File B needs the contents of File A to go before it, all that `#import`'s uniqueness guarantee will do is ensure that one of those files doesn't get its wish, and then you'll get a compile error in that file. – Chuck Sep 14 '11 at 02:04
  • Thank you for the comment, Chuck. I understand your point. However, I cannot reproduce the error this way. I took the example where ActionDispatcher includes GameObject in the header and GameObject includes ActionDispatcher in its header. I the implementations the classes use methods of each other. No compilation errors at all. Would you give me an example of how to reproduce the error? – Davyd Geyl Sep 14 '11 at 02:17
  • OK, I have reproduced it. I was wrong. Dammit! I have never had such kind of error before. Thanks guys! – Davyd Geyl Sep 14 '11 at 03:41