get userData of SKSpriteNode using the scene editor - swift

I set the userData of my SKSpriteNode in the scene editor:
Then I tried to get it, using:
let sprite:SKSpriteNode = self.childNode(withName: "sprite") as? SKSpriteNode
let numero:Int = sprite.userdata?.valueForKey("numero") as! Int
But I got nil value : "fatal error: unexpectedly found nil while unwrapping an Optional value"
I also tried to init the userData with:
sprite.userData? = NSMutableDictionary()
But same result...

Probably also your sprite is nil:
try to search your sprite with the optional binding (if let) and the "//" before sprite.
if let sprite = self.childNode(withName: "//sprite") as? SKSpriteNode {
let numero:Int = sprite.userdata?.valueForKey("numero") as! Int
} else {
print("I cannot find sprite..")
}
It performs a recursive search from its current position.
Check the API reference here.

Related

Simon game, player.delegate error: unexpectedly found nil

I am trying to make this Simon game app for practicing. As shown in the right code in the image attached, the author had 4 players for each color respectively and therefore, 4 delegates.
I tried to simplify it a little bit by using only one player, as shown in the left code. However, I got the error saying "Unexpectedly found nil while unwrapping an optional value". I don't understand why it would be optional as I unwrapped player using !.
What is the reason for the error?
Thanks.
You are trying to assign a value to a property of an object, while the object is nil and not yet initialized.
Move those lines of code
player.delegate = self
player.numberOfLoops = 0
to the playSound function
func playSound(soundName: String) {
let url = Bundle.main.url(forResource: soundName, withExtension: "wav")
player = try! AVAudioPlayer(contentsOf: url!)
player.delegate = self
player.numberOfLoops = 0
player.play()
}

How to programmatically change text of SKLabelNode?

I added some SKLAbelNode into SKNode, which is placed inside SKScene
I need SKNode for grouping some nodes
I added name "altitude" to my SKLAbelNode
and put this code into SKScene class which was associated with my .sks file
var altitude:SKLabelNode = SKLabelNode()
override func sceneDidLoad()
{
if let alti:SKLabelNode = self.childNode(withName: "altitude") as? SKLabelNode {
altitude = alti
}
}
...
override func didMove (...) {
altitude.text = "000"
}
But always I get Fatal error
UPD: I solved this error, but got a question, why when I point a name of sknode even if it's inside in other node and try to get access to it i must point all tree something like
let altitude= (self.childNode(withName: "sknode") as! SKNode).childNode(withName: "altitude") as! SKLabelNode
altitude.text = "000"

How to prevent crashing when tapping off a node

The code that I am writing has a problem where whenever I tap somewhere other than a node (ex. background) the app ends up crashing.
I've tried making an if let statement but it says I can't downcast a SKnode to a more optional type SKSpriteNode.
I've also tried if node.contains(position of touch).
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if let touchLocation = touch?.location(in: self) {
let selectedNode = nodes(at: touchLocation)[0] as! SKSpriteNode
activeObject = selectedNode
storedData = Array(activeObject.name!)
let platformStoredInt = storedData[2]
storedPlatform = Int(platformStoredInt.unicodeScalars.first!.value - Unicode.Scalar("0")!.value)
}
}
Tapping on anything other than the SKSpriteNodes that are considered objects results in a SIGABRT.
The app crashes because you are force unwrapping a value in this line:
let selectedNode = nodes(at: touchLocation)[0] as! SKSpriteNode
So instead, use:
if let selectedNode = nodes(at: touchLocation)[0] as? SKSpriteNode {
activeObject = selectedNode
storedData = Array(activeObject.name!)
let platformStoredInt = storedData[2]
storedPlatform = Int(platformStoredInt.unicodeScalars.first!.value - Unicode.Scalar("0")!.value)
}
Always try to avoid the force unwrapping (as!). Use Optional Chaining instead.
Optional chaining is a process for querying and calling properties, methods, and subscripts on an optional that might currently be nil.

Getting an error while loading data into WKInterfaceTable

I create a watchKit app/extension of my app. I use this func to load the data into the WKInterfaceTable:
// Load table into the data
func loadTableData() {
let sharedDefault = NSUserDefaults(suiteName: "group.com.Devpr.App")
let numberItems = sharedDefault?.objectForKey("numberItems") as? Int
tableView.setNumberOfRows(numberItems!, withRowType: "Cell")
var i = 0
let task = sharedDefault?.objectForKey("\(i)WK") as? String
let row = tableView.rowControllerAtIndex(i) as! TableRowObject // Get a single row object for the current item
row.lblTblRowItem.setText(task) // Set the row text to the corresponding item
i++ // Move onto the next item
}
The app is crashing in this line of the function: let row = tableView.rowControllerAtIndex(i) as! TableRowObject with this error: fatal error: unexpectedly found nil while unwrapping an Optional value. I really can't find anything which is nil.
Image after the crash:
I hope someone of you can help me to solve this. Thanks a lot for you're help!
If numberOfItems is 0, tableView.rowControllerAtIndex(i) can be nil.

Error using subscript of optional array

When using this code:
let result: AnyObject! = hitResults[0]
I am getting the following error:
[AnyObject]? does not have a member named subscript
Containing function for context:
func handleTap(gestureRecognize: UIGestureRecognizer) {
// retrieve the SCNView
let scnView = self.view as SCNView
// check what nodes are tapped
let p = gestureRecognize.locationInView(scnView)
let hitResults = scnView.hitTest(p, options: nil)
// check that we clicked on at least one object
if hitResults?.count > 0 {
// retrieved the first clicked object
let result: AnyObject! = hitResults[0]
// get its material
let material = result.node!.geometry?.firstMaterial
// highlight it
SCNTransaction.begin()
SCNTransaction.setAnimationDuration(0.5)
// on completion - unhighlight
SCNTransaction.setCompletionBlock {
SCNTransaction.begin()
SCNTransaction.setAnimationDuration(0.5)
material?.emission.contents = UIColor.blackColor()
SCNTransaction.commit()
}
material?.emission.contents = UIColor.redColor()
SCNTransaction.commit()
}
}
Does anyone know what the issue here is?
This happens because hitTest returns an optional array, so you need to unwrap before using it.
Instead of checking that the hitResults has a count > 0, you could check that there the first object exists, and then proceed to using that object
if let firstHit = scnView.hitTest(p, options: nil)?.first {
// safely use firstHit here...
}
You can't use a subscript on an optional array. [AnyObject]? Is an optional array of type AnyObject. If you are sure that hitResults is non-nil, you can unwrap it with ! then use a subscript.
let result: AnyObject! = hitResults![0]
Since hitResults is an [AnyObject]?, you can't call subscript on it without unwrapping it first. The safest way to do this is using optional binding, like so:
// check that we clicked on at least one object
if hitResults?.count > 0 {
// retrieved the first clicked object
if let result: AnyObject = hitResults?[0] {
/* safely use result here */
}
}
Or, even better, you can use optional binding with the first property of Array which returns the first element in the array if the Array is not empty, or nil:
// check that we clicked on at least one object and retrieve it
if let result = hitResults?.first {
/* safely use result here */
}