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.

jscs
  • 63,694
  • 13
  • 151
  • 195
Cooper Buckingham
  • 2,503
  • 2
  • 15
  • 23
  • `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. – jscs Sep 09 '14 at 22:25
  • 2
    `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. – jscs Sep 09 '14 at 22:30
  • The question then is, why do you need to use an `NSSet`? Why not an array? – jscs Sep 09 '14 at 22:31
  • 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 pool – Cooper Buckingham Sep 09 '14 at 22:32
  • `-[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:` – jscs Sep 09 '14 at 22:38
  • 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. – Cooper Buckingham Sep 09 '14 at 22:42
  • Had exactly the same issue, thanks – Dvole Oct 31 '14 at 09:17
  • 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... – GilesDMiddleton Jan 02 '15 at 15:10
  • 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. – GilesDMiddleton Jan 02 '15 at 15:27

1 Answers1

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;
}
Cooper Buckingham
  • 2,503
  • 2
  • 15
  • 23
  • 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. – Darrarski Oct 12 '14 at 20:41
  • The same applies to SKNode class. – Darrarski Oct 12 '14 at 20:49
  • 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. – Cooper Buckingham Oct 12 '14 at 23:14
  • @Darrarski 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. – nacross Nov 01 '14 at 08:31