ios sprite-kit exc-bad-access

Ejecutar una acción simple en el nodo secundario de un SKScene causa EXC_BAD_ACCESS en iOS 7.1



sprite-kit exc-bad-access (1)

Me encontré con este error de tiempo de ejecución mientras daba los últimos toques a un juego de SpriteKit que he estado desarrollando. Funciona bien en iOS 8, pero se bloquea en iOS 7.1 (simulador Y dispositivo).

Creé un pequeño proyecto que recrea el problema que estoy tratando. Crea un GameScene al desarchivar un archivo sks creado en el editor provisto dentro de Xcode 6 (al igual que el proyecto de ejemplo generado al crear un nuevo proyecto de SpriteKit). Después de obtener una referencia a un elemento dentro de la escena generada utilizando childNodeWithName: intentar ejecutar una acción simple, se bloquea el programa y se genera EXC_BAD_ACCESS . La modificación directa de las propiedades del sprite parece funcionar bien (ver código).

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { /* Called when a touch begins */ for (UITouch *touch in touches) { CGPoint location = [touch locationInNode:self]; SKSpriteNode *sprite = (SKSpriteNode*)[self childNodeWithName:@"sprite"]; // This works. sprite.position = location; SKAction *action = [SKAction moveByX:100 y:0 duration:1]; // This doesn''t. [sprite runAction:action]; } }

He estado buscando en Internet y en mi propio cerebro y, hasta donde yo sé, no estoy incumpliendo ninguna regla. Por favor, dime que estoy equivocado, y específicamente qué regla estoy rompiendo. Porque si esto resulta ser un problema que no es mi culpa, la frustración sería mucho mayor. ¿Estoy haciendo algo que no está disponible en iOS 7?

Nota: Los únicos cambios que realicé en el proyecto genérico SpriteKit (el de Nave Espacial) es que agregué un sprite rojo simple en el editor SKScene, le di el nombre "sprite" y modifiqué el método touchesBegan: como se muestra arriba.

También Nota: Agregar un sprite programáticamente (como en el proyecto de ejemplo) no plantea este problema, y ​​el uso de childNodeWithName: para obtener una referencia funciona bien. El problema solo parece surgir cuando se accede a un sprite incluido en el archivo sks archivado.

Aquí está la huella en el choque:

* thread #1: tid = 0x4da6c, 0x00000000, queue = ''com.apple.main-thread'', stop reason = EXC_BAD_ACCESS (code=1, address=0x0) frame #0: 0x00000000 frame #1: 0x009b65d7 SpriteKit`SKCSprite::update(double) + 231 frame #2: 0x009b66de SpriteKit`SKCSprite::update(double) + 494 frame #3: 0x0099bd58 SpriteKit`-[SKNode _update:] + 43 frame #4: 0x0097c003 SpriteKit`-[SKScene _update:] + 104 frame #5: 0x009919a4 SpriteKit`-[SKView(Private) _update:] + 253 frame #6: 0x0098f5e1 SpriteKit`-[SKView renderCallback:] + 936 frame #7: 0x0098cea0 SpriteKit`__29-[SKView setUpRenderCallback]_block_invoke + 82 frame #8: 0x009b168f SpriteKit`-[SKDisplayLink _callbackForNextFrame:] + 268 frame #9: 0x009b19ad SpriteKit`-[SKDisplayLink _caDisplayLinkCallback] + 137 frame #10: 0x048cdd66 QuartzCore`CA::Display::DisplayLinkItem::dispatch() + 48 frame #11: 0x048cdc22 QuartzCore`CA::Display::DisplayLink::dispatch_items(unsigned long long, unsigned long long, unsigned long long) + 310 frame #12: 0x048ce147 QuartzCore`CA::Display::TimerDisplayLink::callback(__CFRunLoopTimer*, void*) + 123 frame #13: 0x006d4ac6 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 22 frame #14: 0x006d44ad CoreFoundation`__CFRunLoopDoTimer + 1181 frame #15: 0x006bc538 CoreFoundation`__CFRunLoopRun + 1816 frame #16: 0x006bb9d3 CoreFoundation`CFRunLoopRunSpecific + 467 frame #17: 0x006bb7eb CoreFoundation`CFRunLoopRunInMode + 123 frame #18: 0x02b6a5ee GraphicsServices`GSEventRunModal + 192 frame #19: 0x02b6a42b GraphicsServices`GSEventRun + 104 frame #20: 0x00aa1f9b UIKit`UIApplicationMain + 1225 * frame #21: 0x00061a2d SKTest`main(argc=1, argv=0xbff9f39c) + 141 at main.m:14 frame #22: 0x027606d9 libdyld.dylib`start + 1


Me encontré con esto y aquí hay una solución que he pirateado. Sí, esto no es ideal, pero seguro es mejor que un choque.

Después de cargar su escena, haga una copia del SKSPriteNode y cambie ese nuevo nodo así:

SKSpriteNode *sprite = (SKSpriteNode*)[self childNodeWithName:@"bob"]; SKSpriteNode *newSprite = [sprite copy]; [sprite removeFromParent]; [self addChild:newSprite];

Ahora, puedes acceder a un uso de SKAction en ese nuevo nodo, pero te gusta usar el mismo código que tienes en tu método touchesBegan .

Supongo que una propiedad para nodos basados ​​en .sks de alguna manera no se inicializa correctamente.

Si tiene muchos nodos, probablemente pueda bucle / enumerar a través de ellos para hacer este intercambio.

ACTUALIZAR

El cartel original fue un paso más allá y descubrió que la creación de una copia de GameScene también funcionaba. Por lo tanto, no es necesario pasar por los nodos y hacer copias de forma individual.