Search code examples
swiftsprite-kitswift2skspritenodeuitouch

Swift 2: Value of type 'Set<UITouch>' has no member 'anyObject'


I checked my old game and I want to update it in Swift 2.0. When I tried to fix it, Xcode found an error. Error is Value of type 'Set' has no member 'anyObject' on this line of code:

var touch:UITouch = touches.anyObject() as! UITouch

function:

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {

    self.runAction(SKAction.playSoundFileNamed("torpedo.mp3", waitForCompletion: false))

    var touch:UITouch = touches.anyObject() as! UITouch //<-- Here is Error
    var location:CGPoint = touch.locationInNode(self)

    var torpedo:SKSpriteNode = SKSpriteNode(imageNamed: "torpedo")
    torpedo.position = player.position

    torpedo.physicsBody = SKPhysicsBody(circleOfRadius: torpedo.size.width/2)
    torpedo.physicsBody!.dynamic = true
    torpedo.physicsBody!.categoryBitMask = photonTorpedoCategory
    torpedo.physicsBody!.contactTestBitMask = alienCategory
    torpedo.physicsBody!.collisionBitMask = 0
    torpedo.physicsBody!.usesPreciseCollisionDetection = true

    var offset:CGPoint = vecSub(location, b: torpedo.position)

    if (offset.y < 0){
        return

    self.addChild(torpedo)

    var direction:CGPoint = vecNormalize(offset)

    var shotLength:CGPoint = vecMult(direction, b: 1000)

    var finalDestination:CGPoint = vecAdd(shotLength, b: torpedo.position)

    let velocity = 568/1
    let moveDuration:Float = Float(self.size.width) / Float(velocity)

    var actionArray:NSMutableArray =  NSMutableArray()
    actionArray.addObject(SKAction.moveTo(finalDestination, duration: NSTimeInterval(moveDuration)))
    actionArray.addObject(SKAction.removeFromParent())

    torpedo.runAction(SKAction.sequence(actionArray))
}

So what to fix here ?


Solution

  • Given a Set of UITouch defined as follow

    touches: Set<UITouch>
    

    you can retrieve a touch with this code

    let touch = touches.first
    

    Generics

    There is no need to force cast the retrieved element to UITouch. Infact now the Apple APIs written in Objective-C have been updated with generics. This means that in this case you receive a Set of UITouch (not a Set of NSObject that could literally contains any object). So the Set already knows the contained elements are UITouch.

    Optionals

    The first computed property does return an Optional. Infact if the Set is empty it does return nil.

    A good and safe technique to unwrap the element is

    guard let touch = touches.first else {
        debugPrint("Ops, no touch found...")
        return
    }
    
    // here you can use touch