Sophie McCarrell
Sophie McCarrell

Reputation: 2871

inserting NSNumber into NSDictionary results in 0

I've tried many different things and I can't understand why any integer I put into my dictionary comes out as 0.

self.lastDinoIndex = [[NSMutableDictionary alloc] init];
unsigned index = arc4random_uniform(28);
[self.lastDinoIndex
    setObject:[NSNumber numberWithUnsignedInt:index]
    forKey:dinosaur];
NSLog(@"hmmm %d, %d, %d",
    index,
    [[NSNumber numberWithUnsignedInt:index] unsignedIntValue],
    [self.lastDinoIndex[dinosaur] unsignedIntValue]);

this prints out "hmmmm 8, 8, 0" where 8 is the random number and 0 is the source of my frustration.

Dinosaur is an SKSpriteNode instance.

EDIT: The whole function:

-(id)initWithSize:(CGSize)size {

    if (self = [super initWithSize:size]) {
        self.dinoFNs = @[@"broncosoro.png", @"STEGOZAURUS", @"terrorredacter.png", @"treks.png", @"velorappers.png"];
        self.lastDinoIndex = [[NSMutableDictionary alloc] init];

        /* Setup your scene here */
        self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];

        //That was entirely too difficult to get the background image set properly... holy shit.
        SKSpriteNode *background = [SKSpriteNode spriteNodeWithImageNamed:@"prehistoric_urban_centre"];
        background.anchorPoint = CGPointZero;
        background.position = CGPointZero;
        background.size = self.frame.size;
        [self addChild:background];

        for (NSUInteger i = 0; i < ARRAY_SIZE(points); ++i) {
            SKSpriteNode *anode = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(30, 30)];
            anode.position = points[i];
            [self addChild:anode];
        }

        SKAction *wait = [SKAction waitForDuration:4];
        SKAction *spawnDino = [SKAction runBlock:^{
            SKSpriteNode* dinosaur = [SKSpriteNode spriteNodeWithImageNamed: self.dinoFNs[arc4random_uniform(5)]];
            unsigned index = arc4random_uniform(28);
            [self.lastDinoIndex setObject:[NSNumber numberWithUnsignedInt:index] forKey:dinosaur];
            NSLog(@"hmmm %d, %d, %d",index, [[NSNumber numberWithUnsignedInt:index] unsignedIntValue], [self.lastDinoIndex[dinosaur] unsignedIntValue]);
            dinosaur.position = points[index];
            [self addChild:dinosaur];

            CGFloat duration = 2.0;
            SKAction *moving = [SKAction runBlock:^{
                //get next index
                int curIndex = [self.lastDinoIndex[dinosaur] unsignedIntValue];
                int nextIndex;
                if((curIndex +1) % 5 != 0)
                    nextIndex = ((arc4random_uniform(2) == 1)
                    ? curIndex + 1
                    : curIndex + 5);
                self.lastDinoIndex[dinosaur] = [NSNumber numberWithUnsignedInt: nextIndex];

                NSLog(@"%d => %d", curIndex, nextIndex);

                //TODO: also add option to go down.
                if (nextIndex < 29) {  //at or beyond spawn point
                    NSLog(@"%d: %f, %f", nextIndex, points[nextIndex].x, points[nextIndex].y);
                    [dinosaur runAction:[SKAction moveTo: points[nextIndex] duration:duration]];
                }
                else
                    [dinosaur removeFromParent];
            }];
            SKAction *delayedMoving = [SKAction sequence:@[[SKAction waitForDuration:duration], moving]];
            [dinosaur runAction:[SKAction repeatActionForever: delayedMoving]];
        }];
        SKAction *sequence = [SKAction sequence:@[wait, spawnDino]];

        [self runAction:[SKAction repeatActionForever:sequence]];

    }
    return self;
}

Upvotes: 1

Views: 107

Answers (2)

rdelmar
rdelmar

Reputation: 104082

In my testing, the problem seems to be with how isEqual: is implemented by SKSpriteNode (a bug?). Here is the test code I used,

-(void)doStuff {

    self.dinoFNs = @[@"back1.tiff", @"back2.tiff", @"Baldacci.tiff"];
    self.lastDinoIndex = [[NSMutableDictionary alloc] init];

    SKSpriteNode* dinosaur = [SKSpriteNode spriteNodeWithImageNamed: self.dinoFNs[arc4random_uniform(3)]];
    unsigned index = arc4random_uniform(28);
    [self.lastDinoIndex setObject:[NSNumber numberWithUnsignedInt:index] forKey:dinosaur];
    NSLog(@"hmmm %d, %d",index, [self.lastDinoIndex[dinosaur] unsignedIntValue]);
    NSLog(@"%@",self.lastDinoIndex.allKeys[0]);
    NSLog(@"%@",dinosaur);
    NSLog(@"%d", [dinosaur isEqual:self.lastDinoIndex.allKeys[0]]);
}

And here are the logs,

2014-03-29 18:01:47.811 SpriteNodeDictionaryProblem[2058:60b] hmmm 21, 0
2014-03-29 18:01:47.812 SpriteNodeDictionaryProblem[2058:60b] <SKSpriteNode> name:'(null)' texture:[<SKTexture> 'back2.tiff' (321 x 482)] position:{0, 0} size:{321, 482} rotation:0.00
2014-03-29 18:01:47.812 SpriteNodeDictionaryProblem[2058:60b] <SKSpriteNode> name:'(null)' texture:[<SKTexture> 'back2.tiff' (321 x 482)] position:{0, 0} size:{321, 482} rotation:0.00
2014-03-29 18:01:47.813 SpriteNodeDictionaryProblem[2058:60b] 0

As you can see, when I log dinosaur and self.lastDinoIndex.allKeys[0], the logs are identical, but when I compare them with isEqual:, they come back as not equal. According to the NSDictionary class reference, any object that conforms to NSCopying (which SKSpriteNode does), should be ok as a key.

Upvotes: 2

Chuck
Chuck

Reputation: 237070

self.lastDinoIndex is nil. You need to make sure to create the dictionary created before you use it.

The thing about nil is that it just silently accepts any message you send it and returns the type's "zero" value if it has one (so 0 for integers, 0.0 for floats, NULL/nil for pointers and objects). So mysterious zeros often mean that something is nil.

Upvotes: 3

Related Questions