Lukas H.
Lukas H.

Reputation: 123

Strange behavior of UISwipeGestureRecognizer - micro freezing app

I have a strange problem with Swiperecognizer.

I have spawning objects on screen.

let SpawnObject = SKAction.run({
        () in

        showobject()

    })

    let delay1 = SKAction.wait(forDuration: 0.9)
    let SpawnDelay1 = SKAction.sequence([SpawnObject,delay1])
    let SpawnDelayForever1 = SKAction.repeatForever(SpawnDelay1)
    self.run(SpawnDelayForever1)

    let distance = CGFloat(self.frame.height + 200)
    let moveObject = SKAction.moveBy(x: -distance, y: 0, duration: TimeInterval(0.004 * distance))
    let removeObject = SKAction.removeFromParent()
    moveAndRemove = SKAction.sequence([moveObject,removeObject])

I have object with some physics (Object2, B.png is similar).

func showObject(){
    let texture =  SKTexture(imageNamed: "A.png")
    object = SKSpriteNode(texture: texture)
    object.name = "A"
    object.position = CGPoint(x: 0, y: self.frame.width)
    object.setScale(0.7)
    object.zPosition = 2
    object.run(moveAndRemove)

    object.physicsBody = SKPhysicsBody(texture: texture, size: texture.size())
    object.physicsBody?.categoryBitMask = PhysicsCategory.Object
    object.physicsBody?.collisionBitMask = PhysicsCategory.Object2
    object.physicsBody?.contactTestBitMask = PhysicsCategory.Object2
    object.physicsBody?.affectedByGravity = false
    object.physicsBody?.isDynamic = true


    addChild(object)
}

I have set swipe recognizer in touchesBegan

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches {
        location = touch.location(in: self)
        node = self.atPoint(location)
        if node.name == "A" {
            //node.run(SKAction.moveBy(x: 1000, y: 0, duration: 1)).  //Here I try set action only to touch
            let rightSwipe = UISwipeGestureRecognizer(target: self, action: #selector(rightSlide(_:)))
            rightSwipe.direction = .right
            view!.addGestureRecognizer(rightSwipe)
        }
        else if node.name == "B" {
            //node.run(SKAction.moveBy(x: -1000, y: 0, duration: 1)).   //Here I try set action only to touch
            let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(leftSlide(_:)))
            leftSwipe.direction = .left
            view!.addGestureRecognizer(leftSwipe)
        }else {print ("Blank space")}
    }

}

func leftSlide(_ sender: UISwipeGestureRecognizer){
    if node.name == "B" {
    node.run(SKAction.moveBy(x: -1000, y: 0, duration: 1))
    }else {print ("Bad swipe")}
    }
func rightSlide(_ sender: UISwipeGestureRecognizer){
    if node.name == "A" {
    node.run(SKAction.moveBy(x: 1000, y: 0, duration: 1))
    }else {print ("Bad swipe")}
}

And now the problem. Objects are showing on screen, when I swipe on them, they disappear to side. Everything works fine until I swipe something about 50 objects away, after that every next swipe freeze app for microsecond, objects weird jumps a few pixels down (more swipes, more pixels) and back to their original position and after this weird behavior object swipe away. More swipes = bigger freeze and bigger jumps.

I try turn off physics and nothing. But when I change action directly to touch (no need swipe, just touch), app works fine forever. So there must be wrong swipe recognizer. Or not? I check CPU and MEMORY and CPU has 35% and memory are about 50MB. Nodes on screen max 20. FPS are 60 but when app freeze, it goes down to 58 (Like flickering).

Any suggestion? How to diagnose where is problem? Thanks!

Upvotes: 1

Views: 77

Answers (1)

Whirlwind
Whirlwind

Reputation: 13675

Instead of adding a recognizer every time in touchesBegan method, you should do the following:

1) Create an array to store all recognizers, so you can remove them later easily

2) Add recognizers only once. Note that recognizers are added to the view, not to the scene

3) Remove them when the scene is about to remove from a view

import SpriteKit

class GameScene: SKScene,SKPhysicsContactDelegate {


     var recognizers:[UIGestureRecognizer] = []

    override func didMove(to view: SKView) {


        let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(GameScene.leftSlide(recognizer:)))
        leftSwipe.direction = .left
        leftSwipe.numberOfTouchesRequired = 1
        self.view?.addGestureRecognizer(leftSwipe)
        recognizers.append(leftSwipe)

         //do the same for other recognizers

    }

    func leftSlide(recognizer:UISwipeGestureRecognizer){
        print("Swipe")
    }

//define other methods here to handle other recognizers...

  override func willMove(from view: SKView) {
    super.willMove(from: view)

    for recognizer in recognizers {
        self.view?.removeGestureRecognizer(recognizer)
    }
    recognizers.removeAll()
}
}

Upvotes: 1

Related Questions