Безопасно ли менять SKNode в методе действия распознавателя жестов?

Apple заявляет в https://developer.apple.com/documentation/spritekit/skscenedelegate. :

Изменение объектов SpriteKit за пределами назначенных обратных вызовов (фоновая очередь или что-либо еще, не относящееся к основному потоку) может привести к проблемам, связанным с параллелизмом. Даже диспетчеризация работы основного потока асинхронно или в более позднее время сопряжена с риском, поскольку закрытие, скорее всего, будет выполнено вне периода времени, ожидаемого SpriteKit. Если вы столкнулись с ошибкой сегментации или другим типом сбоя, происходящим глубоко внутри инфраструктуры SpriteKit, велика вероятность того, что ваш код модифицирует объект SpriteKit вне обычных обратных вызовов.

Я использую распознаватели жестов для взаимодействия с объектами набора спрайтов. Простым примером может быть добавление SKAction к узлу, когда пользователь коснулся объекта:

func tapAction(gr:UITapGestureRecognizer) {
    scene.childNode(withName: "balloon")!.run(SKAction.fadeOut(withDuration: 2))
}

Несмотря на то, что это "просто работает" на данный момент, я боюсь, что это не работает в более сложных случаях.

Есть ли намек от Apple, что это разрешено? Или мне действительно нужно отложить модификацию объекта SpritKit от действия жеста до назначенного обратного вызова?


person Klaas    schedule 13.07.2017    source источник
comment
вы в безопасности, вы просто назначаете действие, которое будет выполняться во время обычных обновлений набора спрайтов   -  person Knight0fDragon    schedule 13.07.2017
comment
это кажется мне совершенно нормальным. За исключением того, что принудительная развертка проблематична, если ваш воздушный шар лопнет или что-то в этом роде: P Я бы опасался, если этот жест удалит или изменит физические тела (потому что это всегда вызывает проблемы в didBegin), и в этом случае установка флага, который будет интерпретироваться в вашей игровой сцене, может быть идеальным.   -  person Fluidity    schedule 13.07.2017
comment
@Fluidity воздушный шар никогда не удаляется. Я знаю, как обращаться с опционами :-)   -  person Klaas    schedule 13.07.2017
comment
ха-ха, хорошо, я не нажал на ваше имя, поэтому я не знал, был ли ваш представитель из Java или что-то в этом роде..: P   -  person Fluidity    schedule 13.07.2017


Ответы (1)


Похоже, вы в безопасности, вы просто назначаете действие. Это будет работать во время обычных обновлений набора спрайтов.

если бы вы манипулировали реальным объектом или удаляли узел, у вас возникли бы проблемы. Допустим, вы нажали, чтобы удалить узел. Это нажатие происходит прямо перед didContactBegin. didContactBegin ожидал бы узел, но, увы, вы его удалили, поэтому он рухнет.

Если вы хотите чувствовать себя в безопасности, настройте очередь для запуска в начале вашего обновления.

class GameScene : SKScene
{
   public typealias Closure = ()->()
   public var processOnUpdate = [Closure]()


   override func update(_ currentTime: TimeInterval) {
       proceseOnUpdate.forEach{$0()}
       processOnUpdate = [Closure]()
       ....//do other stuff
   }
}

//SKView Code
func tapAction(gr:UITapGestureRecognizer) {
    scene.processOnUpdate.append(
    { 
       scene.childNode(withName: "balloon")!.run(SKAction.fadeOut(withDuration: 2))
    }}

}

Мои извинения, если это не запускается в первый раз, я сейчас не на Mac, чтобы проверить это.

person Knight0fDragon    schedule 13.07.2017
comment
Разве принудительное разворачивание не является небезопасным, если в какой-то момент воздушный шар будет удален? - person Fluidity; 13.07.2017
comment
@Fluidity, безусловно, Клаас должен решить, как с этим справиться, может быть, воздушный шар никогда не будет удален, я понятия не имею. - person Knight0fDragon; 13.07.2017
comment
По крайней мере, он вызвал сбой и знает, где он лежит, в отличие от того, что он падает где-то во фреймворке и понятия не имеет, где это происходит. - person Knight0fDragon; 13.07.2017
comment
@Knight0fDragon Спасибо за развернутый ответ и мысли! Кажется разумным. - person Klaas; 13.07.2017