Swift/SpriteKit How to check whether SKNode instance is not nil - ios

Why does the following code not work?
if let helloNode: SKNode = self.childNodeWithName("helloNode")! { ... }
self.childNodeWithName("helloNode") returns SKNode?.
! unwraps the return value to SKNode.
helloNode captures SKNode.
What am I doing wrong?

You don't want to unwrap it.
if let helloNode: SKNode = self.childNodeWithName("helloNode") { ... }
The point of if let is to see if the value is not nil before you enter the block. If you unwrap it in the 'if let' statement it defeats the purpose.

Remove the "!". It is not appropriate in an "if let .." context. "If let ..." already unwraps the value.

Related

SpriteKit Unwrap

I am trying to unwrap the speed value of an action to increase it every ten taps, but it doesn't change when I use '?' before the ".speed". If I use '!' it throws an "unwrapping an Optional value" error". How can I fix this issue?
Here's my code
for child in self.children as! [SKSpriteNode] {
if let block: SKSpriteNode = child as? SKSpriteNode {
if (tapCount == 10) {
block.action(forKey: "seq")?.speed += 0.5
block.action(forKey: "seq2")?.speed += 0.5
print(block.action(forKey: "seq2")?.speed)
tapCount = 0
print("YES")
}
}
}
When Swift throws a runtime error and complains about finding nil when unwrapping an Optional value, it means that your code assume some Optional value to be non-nil, when it is nil.
In a really small nutshell:
The ? means: try unwrapping and if it fails, don't continue.
The ! means: unwrap because I guarantee it's not nil.
To answer your question: I assume block.action(forKey: "seq2") returns nil. The action of which you want to alter the speed does not exist.
Note
If the ? and ! operators sound confusing to you, I'd recommend reading through Apple's Swift Programming Language document. It is very useful to gain a good understanding of the tools Swift gives you to deal with potentially missing values.

NSData: unexpectedly found nil while unwrapping an Optional value

It may be the basic swift quetion, But i am new to swift or iOS development. I am getting the error fatal error: unexpectedly found nil while unwrapping an Optional value
For the function bellow
func Call() -> NSData?
{
let nilObj: NSData? = nil
if(false){
// Doing something
}
else
{
return nilObj!
}
}
I just want to return the nil NSData in else condition but i am getting error. I am sure i am missing something obvious, Can anybody help.
You declared nilObj as optional and initialised it with nil. Then in your else clause you are trying to unwrap that. For fixing the issue you just need to remove that !
Change your code to:
func Call() -> NSData?
{
let nilObj: NSData? = nil
if(false)
{
// Doing something
}
else
{
return nilObj
}
}
Well, error says it all! You are trying to forceful unwrap an optional. You should use if let syntax while unwrapping an optional.
Optionals in swift can be confusing at first but it helps to keep in mind that they are just an enum like:
enum Optional<T> {
case None
case Some(T) // swift enums can have data associated to them
}
If you are sure your optional has non-nil value, that is, it is a .Some, you can access this underlying value through the exclamation mark ! operator.
In short, force-unwrapping optional! is saying "Ok, I'm sure this optional contains non-nil value. Give it to me."
This is what's called force-unwrapping. You're telling the system to access the value corresponding to .Some(T) although you're not checking whether your optional is a .Some or a .None. If you force-unwrap with ! and your optional turns out to be a .None, you will get the runtime error you got unexpectedly found nil while unwrapping an Optional value.
As a rule of thumb you should always check your optionals before unwrapping them. In few occasions you should assume an optional is non-nil and force-unwrap it. Even an IBOutlet can turn out to be nil if you try to access it in prepareForSegue for example. XCode automatically makes outlets implicitly unwrapped because for most of your view controller's lifecycle they won't be nil. But you still have to take care for yourself of these less common edge cases in which they are nil.
You can check if an optional has non-nil value the standard way with
if optional != nil {
// force-unwrapping after nil check is fine
optional!.someMethod()
} else {
// 'optional' is nil
}
A more idiomatic way to do it with swift is through optional binding.
// binds the constant 'value' to your optional if it is non-nil
if let value = optional {
value.someMethod()
} else {
// optional is nil
}
A third way to check is with guard statements. The semantics of guard statements is a bit different from the previous ones though. You can also mix guard statements and optional binding.
guard optional != nil else {
// optional is nil.
// by the end of this branch you must exit the block that
// encloses the guard statement, such as with a return or break
return
}
// if control reaches here you're guaranteed optional is non-nil
Guard statements are a neat feature in swift because you can focus on the conditions you want, as opposed to what you don't want. It also keeps the code that handles a violated requirement next to the respective requirement. Compared to doing the same thing with an if statement, guards improve readability by making your intents explicit.
To know more have a look at the basics section of the swift documentation.

Why is Apple using this "if let" code? [duplicate]

This question already has answers here:
Why would I use if and let together, instead of just checking if the original variable is nil? (Swift)
(2 answers)
Closed 7 years ago.
Apple has this segment of code on one of their sample projects:
let existingImage = cache.objectForKey(documentIdentifier) as? UIImage
if let existingImage = existingImage where cleanThumbnailDocumentIDs.contains(documentIdentifier) {
return existingImage
}
why is apple using this if let? Isn't more logical to simply use
if cleanThumbnailDocumentIDs.contains(documentIdentifier) {
return existingImage!
}
???!!
If you use
let existingImage = cache.objectForKey(documentIdentifier) as? UIImage
if let existingImage = existingImage where cleanThumbnailDocumentIDs.contains(documentIdentifier) {
return existingImage
}
This will make sure that if existingImage == nil,it will not
execute return existingImage.
Besides,if let also unwrap existingImage from UIImage? to
UIImage
As Abhinav mentioned above, Apple introduced a new type called optional type with Swift.
What does optional mean?
Short and Sweet, "Optional types are types, which can contain a value of a particular data type or nil".
You can read more about optionals and their advantages here : swift-optionals-made-simple
Now whenever you want to make use of value present in an optional type, first you need to check what it contains i.e. does it contains a proper value or it contains nil. This process is called optional unwrapping.
Now there are two types of unwrapping,
Forced unwrapping : If you're sure that an optional will have an value all the time, you can then unwrap the value present in the optional type using "!" mark. This is force unwrapping.
The one more way is to use if let expression, this is safe unwrapping, here you'll check in your program that, if optional has a value you will do something with it; if it doesn't contain value you'd do something else. A simple example is this (You can test this in play ground:
func printUnwrappedOptional (opt:String?) {
if let optionalValue = opt { //here we try to assign opt value to optionalValue constant, if assignment is successful control enters if block
println(optionalValue) // This will be executed only if optionalValue had some value
}
else {
println("nil")
}}
var str1:String? = "Hello World" //Declaring an optional type of string and assigning it with a value
var str2:String? //Declaring an optional type of string and not assigning any value, it defaults to nil
printUnwrappedOptional(str1) // prints "Hello World"
printUnwrappedOptional(str2) // prints "nil"
Hope this clears your question, read through the link given above it'll be more clear to you. Hope this helps. :)
Edit: In Swift 2.0, Apple introduced "guard" statements, once you're good with optionals go through this link, guard statement in swift 2. This is another way to deal with optionals.
Using if let, makes sure that the object (existingImage) is not nil, and it unwraps it automatically, so you are sure inside the if that the condition is true, and the object is not nil, and you can use it without unwrap it !
With Swift, Apple has introduced a new concept/type - Optional Type. I think you better go through Apple Documentation.
Swift also introduces optional types, which handle the absence of a
value. Optionals say either “there is a value, and it equals x” or
“there isn’t a value at all”. Optionals are similar to using nil with
pointers in Objective-C, but they work for any type, not just classes.
Optionals are safer and more expressive than nil pointers in
Objective-C and are at the heart of many of Swift’s most powerful
features.
existingImage is an optional (as? UIImage) and therefor needs to be unwrapped before used, otherwise there would be a compiler error. What you are doing is called forced unwrapping via !. Your program will crash, if existingImage == nil and is therefor only viable, if you are absolutely sure, that existingImage can't be nil
if let and optional types is more help where is there is changes to get nil values to void crashes and unwanted code executions.
In Swift 2.0,
guard
will help us lot where our intention is clear not to execute the rest of the code if that particular condition is not satisfied

How to create a pointer/pass parameter to function in Swift

I am struggling to find the answer for this simply because I am unsure what to search for.
In objective-C I would do something like this to get a pointer to an object of a specific class:
CustomLabelClass *detailLabel = (CustomLabelClass *)[sortCell.contentView viewWithTag:kSortDetailLabelTag];
I would like to do the same in Swift. Basically I detect collision in Sprite Kit Scene and then try and pass the Node (which I know is of a specific class to another function).
if ((contact.bodyA.node?.isKindOfClass(TapCircleIcon)) != nil) {
updateOnScreenStatusFor(...)
I need to pass the TapCircleIcon into the function replacing '...'. So in Obj-c I would do something like:
TapCircleIcon *tapCircle = (TapCircleIcon *)[contact.bodyA.node];
You no longer need isKindOfClass in Swift. I am assuming that node is an AnyObject? optional. You can cast it to TapCircleIcon and unwrap the optional using this if statement.
if let tapCircleIcon = contact.bodyA.node as? TapCircleIcon {
updateOnScreenStatusFor(tapCircleIcon)
} else {
// node is not a TapCircleIcon
}

How to check for an undefined or null variable in Swift?

Here's my code:
var goBack: String!
if (goBack == "yes")
{
firstName.text = passFirstName1
lastName.text = passLastName1
}
All I want to do is execute the if-statement if 'goBack' is undefined. How can I do that? (I don't know what to put in the blank)
The overall program is more complicated which is why I need the variable to be undefined at first. In short, I'm declaring 'goBack', asking the user to type in their first and last name, then continuing to the next view controller. That view controller has a back button that brings us back to the first view controller (where I declared 'goBack'). When the back button is pressed, a 'goBack' string is also passed of "yes". I also passed the first and last name to the next view controller but now I want to pass it back. I'm able to pass it back, its just a matter of making the text appear.
EDIT: firstName and lastName are labels while passFirstName1 and passLastName1 are variables from the second view controller.
"All I want to do is execute the if-statement if 'goBack' is undefined. How can I do that?"
To check whether a variable equals nil you can use a pretty cool feature of Swift called an if-let statement:
if let goBackConst = goBack {
firstName.text = passFirstName1
lastName.text = passLastName1
}
It's essentially the logical equivalent of "Can we store goBack as a non-optional constant, i.e. can we "let" a constant = goBack? If so, perform the following action."
It's really interesting, you can define a variable as optional, which means it may or may not be defined, consider the following scenerio:
you want to find out if the app has been installed before...
let defaults = NSUserDefaults()
let testInstalled : String? = defaults.stringForKey("hasApplicationLaunchedBefore")
if defined(testInstalled) {
NSLog("app installed already")
NSLog("testAlreadyInstalled: \(testInstalled)")
defaults.removeObjectForKey("hasApplicationLaunchedBefore")
} else {
NSLog("no app")
defaults.setValue("true", forKey: "hasApplicationLaunchedBefore")
}
Then all you need to do is write a function to test for nil...
func defined(str : String?) -> Bool {
return str != nil
}
And you've got it. A simpler example might be the following:
if let test : String? = defaults.stringForKey("key") != nil {
// test is defined
} else {
// test is undefined
}
The exclamation mark at the end is to for unwrapping the optional, not to define the variable as optional or not
"All I want to do is execute the if-statement if 'goBack' is undefined"
The guard statement (new in Swift 2) allows exactly this. If goBack is nil then the else block runs and exits the method. If goBack is not nil then localGoBack is available to use following the guard statement.
var goBack:String?
func methodUsingGuard() {
guard let localGoBack = goBack else {
print("goBack is nil")
return
}
print("goBack has a value of \(localGoBack)")
}
methodUsingGuard()
From The Swift Programming Language (Swift 3.1):
Constants and variables created with optional binding in an if
statement are available only within the body of the if statement. In
contrast, the constants and variables created with a guard statement
are available in the lines of code that follow the guard statement, as
described in Early Exit.

Resources