SKSpriteNode pools in iOS 8 seem to be allocated to overlapping memory
Asked Answered
F

1

4

I might be missing something. But my current app on the appstore works in iOS 7, but in iOS 8 completely fails because it won't create a preallocated pool of sprites. They appear to be written to the same address unless the sprites have specifically different properties.

In iOS 7 the following code produces a set with 4 unique objects. In iOS 8, the same code produces a set with only 1 object:

  NSMutableSet *aSet = [NSMutableSet set];
  SKColor *sameColor = [SKColor redColor];
  CGSize sameSize = CGSizeMake(10, 10);

  for (int i = 0; i < 4; i++) {

      //allocate a brand new sprite
      SKSpriteNode *thisSprite1 = [[SKSpriteNode alloc] initWithColor:sameColor size:sameSize];

      [aSet addObject:thisSprite1];

  }

NSLog(@"aSet Count: %i", aSet.count);

iOS8 Result:

2014-09-09 15:06:43.065 MSM[383:27490] aSet Count: 1

Am I going crazy? Amazingly, pretty much my entire app is based on this code concept repeated over and over again. If I do the same thing, but use something like NSObject, then the problem goes away, so it appears to be a new change to SKSprite. I know I can work around it with some crazy stuff, but is a huge pain, since I shouldn't have to do that, and I was hoping to avoid another version submission.

Fleenor answered 9/9, 2014 at 22:14 Comment(9)
isEqual: is not (necessarily) a comparison of addresses. It is for semantic comparison; each class implements it to define what "equality" is for its particular properties.Jandy
NSSet uses -hash and -isEqual: to determine membership. That still doesn't have anything to do with the memory addresses of the sprites. It just means that the implementation of -[SKSprite isEqual:] was changed between iOS 7 and 8, possibly away from comparing addresses and to comparing member data.Jandy
The question then is, why do you need to use an NSSet? Why not an array?Jandy
So regardless, that's why I was trying to avoid saying I was using an NSset so that folks didn't say "why are you using an NSSet". I am using pools of sprites which are pre-allocated, so NSMutable set is great for that, since I don't have to worry about dumping the same object back into the poolFleenor
-[NSArray indexOfObjectIdenticalTo:] will tell you if an object with the same address exists in the array already. Or you could subclass SKSpriteNode to re-implement address comparison in isEqual:Jandy
Hmm, re-implement isEqual in a subclass I had not thought of, either way, with the replacing sets with arrays, or sprites with subclasses I'll have to edit most visible classes. But thanks. Looks like my only options.Fleenor
Had exactly the same issue, thanksNoahnoak
I've had a similar issue where an NSMutableArray of simple classes derived from NSObjects now requires derivations to implement 'name' when containsObject is called on the array (presumably via isEqual). I can demonstrate this behaviour doesn't happen on iOS 7 but does on iOS8. Which is rather annoying...Discontinuity
My issue is that I have mixed classes, some SKNode and some NSObject derived - and when SKNode::IsEqual is called it uses Name of both objects, and the selector isn't recognised on my NSObject. - This behaviour isn't so on 7.1. SKNode::isEqual doesn't select 'name' of the RHS.Discontinuity
F
5

Thanks to Josh for the direction on how to solve this new bump in the road.

I subclassed SKSpriteNode, overriding -isEqual and -hash, to both be what my best guess at the NSObject implementation is. Then just did a Find/Replace All in Project for "SKSpriteNode" for my subclass name, and all is back to it was in the iOS 7 build:

-(BOOL)isEqual:(id)object{

    return self == object;
}

- (NSUInteger)hash
{
    return (NSUInteger)self;
}
Fleenor answered 10/9, 2014 at 0:44 Comment(4)
Should we be aware of some side effects of that solution? I wonder, why Apple decided to change isEqual behaviour in iOS 8 for SKSpriteNode objects.Unpractical
The same applies to SKNode class.Unpractical
No clue. It's possible they could somehow rely on equality to handle some future system. For every line of code I've written using sprite kit it would never make any sense that I can see.Fleenor
@Unpractical I would not be worried about side effects, as mentioned by Josh Caswell it seems they changed the implementation from using memory address for comparison to basing the equality and hash code generation on the actual values set inside the SKNode. Often child nodes will have completely identical values to other child nodes elsewhere in your node hierarchy. This means that when compared to each other in using isEqual and hash methods they will appear the same. It is perfectly safe to implement these methods yourself as long as read up on how to do it properly.Reddy

© 2022 - 2024 — McMap. All rights reserved.