Edited at

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

More than 3 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