Si-N
Si-N

Reputation: 1505

Objective C enumeration type in object changing on reassignment

I have searched and can't find the assert to this. I know it must be a fundamental thing I'm missing here.

I have an enum:

typedef enum  {
    NINETYBEND, NINETYBEND_FAST, NINETYBEND_SLOW, STRAIGHT
} BlockTypeEnum;

I am trying to use these values in objects I am creating like this:

BlockTypeEnum blockType = STRAIGHT;
XMLLevelPiece* piece = [[XMLLevelPiece alloc] init];
[piece initPiece:blockType];

My problem occurs when I try to use the same variable twice. If I create one object with an enum, change the enum and then create a second object using it, the enum in my first object changes to the second enum value. This is not what I want. Example below:

BlockTypeEnum blockType = STRAIGHT;

XMLLevelPiece* piece = [[XMLLevelPiece alloc] init];
[piece initPiece:blockType];

blockType = NINETYBEND_FAST;

XMLLevelPiece* piece2 = [[XMLLevelPiece alloc] init];
[piece2 initPiece:blockType];

NSLog([NSString stringWithFormat:@"%d", [piece getBlockType]]);
NSLog([NSString stringWithFormat:@"%d", [piece2 getBlockType]]);

//BOTH BLOCK TYPES ARE NOW NINETYBEND_FAST, NOT WHAT I WANTED!!

As far as I understood, an enum is just a glorified int, not a pointer, and I am reassigning the variable after adding to the first object. Please can someone tell me what I'm missing! Thanks very much, Simon.

Here is my code for XMLPiece, thanks!

#import "XMLLevelPiece.h"
#import "BlockType.h"
#import "GridCord.h"
#import "BlockColor.h"

@implementation XMLLevelPiece

BlockTypeEnum mBlockType;
BlockColorEnum mBlockColor;
int mRotation;
GridCord* mGridCords;
BlockColorEnum mLeftColor;
BlockColorEnum mTopColor;
BlockColorEnum mRightColor;
Boolean mRotatable;
Boolean mMoveable;
int mGroupID;

-(id) init
{
    if( (self=[super init])) {

    }
    return self;
}

-(void)initPiece:(BlockTypeEnum)pBlockType pBlockColor:(BlockColorEnum)pBlockColor pRotation:(int)pRotation pGridCords:(GridCord*)pGridCords pLeftColor:(BlockColorEnum) pLeftColor pTopColor:(BlockColorEnum) pTopColor pRightColor:(BlockColorEnum) pRightColor pRotatable:(Boolean) pRotatable pMoveable:(Boolean) pMoveable pGroupID:(int) pGroupID
{
    mBlockType = pBlockType;
    mBlockColor = pBlockColor;
    mRotation = pRotation;
    mGridCords = pGridCords;
    mLeftColor = pLeftColor;
    mTopColor = pTopColor;
    mRightColor = pRightColor;
    mRotatable = pRotatable;
    mMoveable = pMoveable;
    mGroupID = pGroupID;
}

-(void)initPiece2
{
    NSLog(@"poo");
}

-(Boolean)getRotatable
{
    return mRotatable;
}

-(Boolean)getMoveable
{
    return mMoveable;
}

-(int) getGroupID
{
    return mGroupID;
}

-(BlockColorEnum) getLeftColor
{
    return mLeftColor;
}

-(BlockColorEnum) getTopColor
{
    return mTopColor;
}

-(BlockColorEnum) getRightColor
{
    return mRightColor;
}

-(BlockTypeEnum) getBlockType
{
    return mBlockType;
}

-(BlockColorEnum) getBlockColor
{
    return mBlockColor;
}

-(int) getRotation
{
    return mRotation;
}

-(id) getGridCords
{
    return mGridCords;
}

-(void) setRotatable:(Boolean) pRotatable 
{
    mRotatable = pRotatable;
}

-(void) setMoveable:(Boolean) pMoveable 
{
    mMoveable = pMoveable;
}

@end

Upvotes: 1

Views: 380

Answers (2)

Paul.s
Paul.s

Reputation: 38728

TL;DR

The answer is - that is not how you define ivars in Objective-C. I'm not even sure how that is supposed to behave but I can reproduce the error if I code it the same as you have.

I'd be interested for someone with more knowledge to explain what the behaviour/scope of those variable should be when they are defined like you have.


There's a lot of flaws in that code

You have not actually shown an initPiece:.

The long init... with all the arguments is likely a bad idea. Generally only add things to an init as either a convenience or if the object simply cannot function without it.

The use of get is not really correct in Objective-C

The class should potentially be defined more like

XMLLevelPiece.h

// You will need to import the header with the BlockTypeEnum defined

@interface XMLLevelPiece : NSObject

@property (nonatomic, assign) BlockTypeEnum blockType;
// .. Other properties

- (id)initWithPiece:(BlockTypeEnum)blockType; // I'm not so sure you need this

@end

XMLLevelPiece.m

#import "XMLLevelPiece.h"
#import "BlockType.h"
#import "GridCord.h"
#import "BlockColor.h"

@implementation XMLLevelPiece

@synthesize blockType = mBlockType;

- (id)initWithPiece:(BlockTypeEnum)blockType;
{
    self = [super init];
    if (self) {
        mBlockType = blockType;
    }
    return self;
}

@end

Then you can use it like

BlockTypeEnum blockType = STRAIGHT;

XMLLevelPiece *p1 = [[XMLLevelPiece alloc] initWithPiece:blockType];

blockType = NINETYBEND_FAST;

XMLLevelPiece *p2 = [[XMLLevelPiece alloc] initWithPiece:blockType];

NSLog(@"%d", p1.blockType);
NSLog(@"%d", p2.blockType);

Which for me results in:

2012-01-08 15:29:31.782 Untitled[1297:707] 3
2012-01-08 15:29:31.791 Untitled[1297:707] 1

Optional observations

If you can do away with the dedicated initializer, the usage would look more like:

BlockTypeEnum blockType = STRAIGHT;

XMLLevelPiece *p1 = [[XMLLevelPiece alloc] init];
p1.blockType = blockType;
// all other assignments

blockType = NINETYBEND_FAST;

XMLLevelPiece *p2 = [[XMLLevelPiece alloc] init];
p2.blockType = blockType;
// all other assignments

NSLog(@"%d", p1.blockType);
NSLog(@"%d", p2.blockType);

To remove a couple of superflous lines you could remove the local blockType variable and assign the value straight to the object:

XMLLevelPiece *p1 = [[XMLLevelPiece alloc] init];
p1.blockType = STRAIGHT;

Upvotes: 1

zaph
zaph

Reputation: 112875

Your method call to initWithPiece does not match the definition.

Call:

[piece initPiece:blockType];

Definition:

-(void)initPiece:(BlockTypeEnum)pBlockType pBlockColor:(BlockColorEnum)pBlockColor pRotation:(int)pRotation pGridCords:(GridCord*)pGridCords pLeftColor:(BlockColorEnum) pLeftColor pTopColor:(BlockColorEnum) pTopColor pRightColor:(BlockColorEnum) pRightColor pRotatable:(Boolean) pRotatable pMoveable:(Boolean) pMoveable pGroupID:(int) pGroupID

Comments:

In general method calls with more than a few parameters are best a poor idea. Probably better in this case is using individual setters.

The convention in Objective-C as per Apple is to name getters without the "get" prefix. In fact a get prefix signifies a value returned via a reference parameter, not as the return result. Such usage will confuse the Analyzer and cause problems if using ARC.

Upvotes: 1

Related Questions