cocos2d/cocos2d-iphone — pull request #260 by pierredavidbelanger (2012-11-04 18:01:49+00:00)
Title: Fix EventsTest problems (OSX touch inconsistency, Dangling pointer)

A little refactor of the TouchTest test in the OSX EventsTest target.

This refactor fixes two problem:

1: OSX touch inconsistency.

It seems OSX (at least on 10.8.2 here) suffer from a strange problem with the way it handle touches. There is two problems here:

1.1: When we leave the app using an OSX gesture (MissionControl, Exposé), OSX will never call the `NSResponder.touchesEndedWithEvent` nor `NSResponder.touchesCancelledWithEvent`, but when we get back to the app, the previously touching `NSTouch` will be released before the app had the time to notice it.

1.2: I found that in some circumstances (quickly touching/releasing the trackpad, easy reproducible with the MagicTrackpad as there is more lag due to Bluetooth), OSX will not consistently call its callbacks.
For example, one quickly tap (touch/release) 4 fingers on the trackpad, here is an expected sequence of callback (it may vary, since its a matter of millisecond):
- `touchesBeganWithEvent` with a count of 3 in `touchesMatchingPhase:NSTouchPhaseBegan`
- `touchesBeganWithEvent` with a count of 1 in `touchesMatchingPhase:NSTouchPhaseBegan`
- `touchesEndedWithEvent` with a count of 2 in `touchesMatchingPhase:NSTouchPhaseEnded`
- `touchesEndedWithEvent` with a count of 2 in `touchesMatchingPhase:NSTouchPhaseEnded`

But, sometime, one can see this sequence:
- `touchesBeganWithEvent` with a count of 3 in `touchesMatchingPhase:NSTouchPhaseBegan`
- `touchesBeganWithEvent` with a count of 1 in `touchesMatchingPhase:NSTouchPhaseBegan`
- `touchesEndedWithEvent` with a count of 2 in `touchesMatchingPhase:NSTouchPhaseEnded`
- `touchesEndedWithEvent` with a count of 1 in `touchesMatchingPhase:NSTouchPhaseEnded`

So the application thinks that there is still a finger touching the trackpad, since 4 touches matches the `NSTouchPhaseBegan` but only 3 matches `NSTouchPhaseEnded`.

2: Dangling pointer.

Given that the code uses `CCSprite.userData` to store the `NSTouch.identity`,
and given that the `NSTouch` are released (along with their `identity`) when we get back from an OSX gesture,
The app crash when trying to test if an old `NSTouch.identity` stored in `CCSprite.userData` is equals to a new `NSTouch.identity`,
at this line:
`if([identity isEqual:[sprite userData]])`

So the refactor was to:

- not rely only on `touchesEndedWithEvent` nor `touchesCancelledWithEvent` to detect that fingers are released from the trackpad. But instead, the state of the `CCSprite` is reset on `touchesBeganWithEvent` using all `touchesMatchingPhase:NSTouchPhaseTouching`.
- use `CCSprite.userObject` to store the `NSTouch.identity`, thus preventing it from begin released along with its `NSTouch` when resuming the app after an OSX gesture.

Suggestions, comments and critics are welcome :)