Help us understand the problem. What is going on with this article?

SKShapeNodeをiOS7.1で使うとクラッシュする

More than 5 years have passed since last update.

SwiftのSpritekitでSKShapeNodeを用いるとiOS7.1でアプリが頻繁に落ちたのでメモ。
なお、SKShapeNodeは丸型や角丸四角などの自由な形の図形を描画したいときに用います。

以下のコードは角丸の図形を描画するコードでiOS8.1シミュレータ環境では正常に動きます。

Swift
override func didMoveToView(view: SKView) {
    let tmpRect = CGRectMake(0.0, 0.0, 400, 100)
    let path = CGPathCreateWithRoundedRect(tmpRect, 9, 9 , nil)

    let blackRect = SKShapeNode(rect: tmpRect, cornerRadius: 10)

    blackRect.fillColor = SKColor.blackColor()
    blackRect.position = CGPoint(x: self.frame.width/2-blackRect.frame.width/2, y: self.frame.height/2)
    self.addChild(blackRect)
}

しかし、iOS7.1環境では

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[SKShapeNode shapeNodeWithRect:cornerRadius:]: unrecognized selector sent to class 0x10614a300'

とエラーを吐いてクラッシュしてしまいます……。
このエラーは下記のコードのようにインスタンスを生成してからパスを加えることで回避することができます。

Swift
override func didMoveToView(view: SKView) {
    let tmpRect = CGRectMake(0.0, 0.0, 400, 100)
    let path = CGPathCreateWithRoundedRect(tmpRect, 9, 9 , nil)

    let blackRect = SKShapeNode()
    blackRect.path = path

    blackRect.fillColor = SKColor.blackColor()
    blackRect.position = CGPoint(x: self.frame.width/2-blackRect.frame.width/2, y: self.frame.height/2)
    blackRect.zPosition = 10
    self.addChild(blackRect)
}

しかし、このコードもiOS7.1上では問題があります。
iOS7.1にバグがあるのか、画面遷移時にアプリが稀にクラッシュしてしまいます。

xcode - Sprite Kit iOS 7.1 crash on removeFromParent - Stack Overflow
http://stackoverflow.com/questions/22399278/sprite-kit-ios-7-1-crash-on-removefromparent

例えば以下のようなコードで生成されたシーンから他のシーンに移動すると稀にクラッシュします。
(クラッシュを起きやすくさせるためにラベルの数を増やしてます)

Swift
override func didMoveToView(view: SKView) {
    /* Setup your scene here */
    makeLabel("hogehoge", yPosition: 100)
    makeLabel("hogehoge", yPosition: 250)
    makeLabel("hogehoge", yPosition: 400)
    makeLabel("hogehoge", yPosition: 550)
    makeLabel("hogehoge", yPosition: 700)
    makeLabel("hogehoge", yPosition: 100)
    makeLabel("hogehoge", yPosition: 250)
    makeLabel("hogehoge", yPosition: 400)
    makeLabel("hogehoge", yPosition: 550)
    makeLabel("hogehoge", yPosition: 700)
}

func makeLabel(labelText:String, yPosition:CGFloat){
    let myLabel = SKLabelNode(fontNamed: "PixelMplus12-Regular")
    myLabel.text = labelText
    myLabel.fontSize = 35

    let tmpRect = CGRectMake(0.0, 0.0, 400, 100)
    let blackRect = SKShapeNode()
    let path = CGPathCreateWithRoundedRect(tmpRect, 9, 9 , nil)

    blackRect.path = path
    blackRect.fillColor = SKColor.blackColor()
    blackRect.strokeColor = SKColor.whiteColor()
    myLabel.position = CGPointMake(blackRect.frame.width/2, myLabel.frame.size.height*1/3)
    blackRect.position = CGPoint(x: self.frame.width/2-blackRect.frame.width/2, y: yPosition)
    blackRect.addChild(myLabel)
    self.addChild(blackRect)
}

対応策としては以下のStack Overflowで述べられているように画面遷移前にNodeを全てcleanするのが一番簡単です。

objective c - SKShapeNode producing crash sometimes on dealloc EXC_BAD_ACCESS - Stack Overflow
http://stackoverflow.com/questions/25385510/skshapenode-producing-crash-sometimes-on-dealloc-exc-bad-access

Swift
func cleanUpChildrenAndRemove(node:SKNode) {
    for child in node.children {
        cleanUpChildrenAndRemove(child as SKNode)
    }
    node.removeFromParent()
}

他にスマートな解決策があったら教えて下さい _(:3」∠)_

以下まとめ。
ir77/TestSKShapeNode
https://github.com/ir77/TestSKShapeNode

uc18uc
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away