Use of unresolved identifier in Swift - ios

I am trying to create an if statement or a switch statement and created a variable to be used.
if (randomIcon == 1) {
var coolCircle = TapCircleIcon(typeOfCircle: CircleType.Circle1)
}
addChild(coolCircle)
The issue I get is unresolved identifier for coolCircle. This is kind of expected, but I am not sure what the swift equvilant would be.
In Obj-C I would probably set the pointer to nil, then create it if the value exists. How would I get this to parse correctly in Swift. What should I do to set the variable to TapCircleIcon class, but not create an object until the if/switch statement?

Simpler:
if (randomIcon == 1) {
let coolCircle = TapCircleIcon(typeOfCircle: CircleType.Circle1)
addChild(coolCircle)
}
More flexible:
let coolCircle: TapCircleIcon?
if (randomIcon == 1) {
coolCircle = TapCircleIcon(typeOfCircle: CircleType.Circle1)
}
else {
coolCircle = nil // or something else
}
if let coolCircle = coolCircle { // not nil
addChild(coolCircle)
}

Since the other answers don't explain anything:
You declare the variable coolCircle inside the if block which makes it available to that if block only. That means you will not be able to use it outside again.
I would go with what #fluidsonic's answer to fix the problem.
Hope that helps your understanding :)

Related

Contains where syntax different when placed in own method in Swift

I am trying to refactor some code out of one method into its own method but the compiler is complaining.
This code works fine inside a longer method
let aboutLocation = self.locationWords.contains(where: {$0.caseInsensitiveCompare((newmessage)!) == .orderedSame})
if (aboutLocation) {
self.startLocationServices()
}
When I try to place the code in its own method as follows it gives error message: Extraneous argument label 'where' in call and suggests I delete the word.
func startLocationServicesIfLocation(newmessage:String){
let aboutLocation = self.locationWords.contains(where: {$0.caseInsensitiveCompare((newmessage)!) == .orderedSame})
if (aboutLocation) {
self.startLocationServices()
}
}
Why would it be different inside one method compared with the other
The error is misleading.
In the function the parameter newmessage is non-optional so you have to remove the exclamation mark (and the enclosing parentheses – also around the if condition – anyway).
let aboutLocation = self.locationWords.contains(where: {$0.caseInsensitiveCompare(newmessage) == .orderedSame})
if aboutLocation { ...
But you can indeed omit the where parameter label using trailing closure syntax
let aboutLocation = locationWords.contains{ $0.caseInsensitiveCompare(newmessage) == .orderedSame }

why I have to unwrap value before I use

A block is defined like below
// Declare block ( optional )
typealias sorting = (([Schedule], [String]) -> [Schedule])?
var sortSchedule: sorting = { (schedules, sortDescription) in
var array = [Schedule]()
for string in sortDescription
{
for (index, schedule) in schedules.enumerate()
{
if string == schedule.startTime
{
array.append(schedule)
break
}
}
}
return array
}
At some points, I am invoking a block by doing
let allSchedules = sortSchedule?(result, sortDescription())
for schedule in allSchedules // Xcode complains at here
{
..........
}
Im using ? because I want to make sure that if the block exists, then do something. However, Xcode complains for the for loop
value of optional type [Schedule]? not upwrapped, did you mean to use '!' or '?'?
Im not sure why because the return type of a block is an array which can have 0 or more than one items.
Does anyone know why xcode is complaining.
You are use ? in line let allSchedules = sortSchedule?(result, sortDescription()) not "for sure that if the block exists", but just for note, that you understand that it can be nil. Behind scene allSchedules have type Array<Schedule>?. And you can not use for in cycle for nil. You better use optional binding:
if let allSchedules = sortSchedule?(result, sortDescription())
{
for schedule in allSchedules
{
//..........
}
}

Best way to check a nil object

I am checking for nil object like this:
if let _ = object {
// Nothing to do here.
} else {
// There's something that must be done here.
}
I would like to remove the part let _ = object because there's nothing to execute inside it. Aside from using if object == nil, what is the best way using the optional checking to verify if a certain object is nil?
If your only intention is to check if the object is nil,
and the unwrapped value is never needed, then
a simple comparison with nil is the simplest way:
if object == nil {
print("Warning: object is nil")
}
If you want to emphasize that this check is a precondition and you want to leave the
current scope if the condition is not satisfied, then you can use
a guard statement. But there is no need to unwrap the object to the unused variable:
guard object != nil else {
print("Warning: object is nil")
return
}
You can use guard statement for this purpose
guard let _ = object else {
// Do something
return
}

How to check which class an item is in Swift 2?

I have a function that is passed an item, the item could be either one of two object classes. I'm trying to test the item for a variable that only exists in one of the classes to identify which of the two classes it is. I'm not sure what the correct way to do this is. I'm trying:
let theItem = item as! ObjectOne
if let objectOneUniqueVariable = theItem.uniqueVariable {
print("It's an instance of ObjectOne")
//Do more things
} else {
theItem = item as! ObjectTwo
print("It's an instance of ObjectTwo")
//Do more things
}
The uniqueVariable is a sting - I'm currently getting the error:
Initialiser for conditional binding must have Optional type, not 'String'
I can add what ever I need to Object One in order for this test to work. Any ideas?
Swift has an elegant solution: Switch on the class type.
switch item {
case let object1 as ObjectOne:
print("It's an instance of ObjectOne")
//Do more things
case let object2 as ObjectTwo:
print("It's an instance of ObjectTwo")
//Do more things
default:
println("something else")
}
In the minimal case if you only cared about getting the value if it's the type of object1, a minimalist way of getting an optional is:
let optionalValue = (item as? ObjectOne)?.theMember
You could then unwrap it, if/when you need it.

Swift: Testing optionals for nil

I'm using Xcode 6 Beta 4. I have this weird situation where I cannot figure out how to appropriately test for optionals.
If I have an optional xyz, is the correct way to test:
if (xyz) // Do something
or
if (xyz != nil) // Do something
The documents say to do it the first way, but I've found that sometimes, the second way is required, and doesn't generate a compiler error, but other times, the second way generates a compiler error.
My specific example is using the GData XML parser bridged to swift:
let xml = GDataXMLDocument(
XMLString: responseBody,
options: 0,
error: &xmlError);
if (xmlError != nil)
Here, if I just did:
if xmlError
it would always return true. However, if I do:
if (xmlError != nil)
then it works (as how it works in Objective-C).
Is there something with the GData XML and the way it treats optionals that I am missing?
In Xcode Beta 5, they no longer let you do:
var xyz : NSString?
if xyz {
// Do something using `xyz`.
}
This produces an error:
does not conform to protocol 'BooleanType.Protocol'
You have to use one of these forms:
if xyz != nil {
// Do something using `xyz`.
}
if let xy = xyz {
// Do something using `xy`.
}
To add to the other answers, instead of assigning to a differently named variable inside of an if condition:
var a: Int? = 5
if let b = a {
// do something
}
you can reuse the same variable name like this:
var a: Int? = 5
if let a = a {
// do something
}
This might help you avoid running out of creative variable names...
This takes advantage of variable shadowing that is supported in Swift.
Swift 3.0, 4.0
There are mainly two ways of checking optional for nil. Here are examples with comparison between them
1. if let
if let is the most basic way to check optional for nil. Other conditions can be appended to this nil check, separated by comma. The variable must not be nil to move for the next condition. If only nil check is required, remove extra conditions in the following code.
Other than that, if x is not nil, the if closure will be executed and x_val will be available inside. Otherwise the else closure is triggered.
if let x_val = x, x_val > 5 {
//x_val available on this scope
} else {
}
2. guard let
guard let can do similar things. It's main purpose is to make it logically more reasonable. It's like saying Make sure the variable is not nil, otherwise stop the function. guard let can also do extra condition checking as if let.
The differences are that the unwrapped value will be available on same scope as guard let, as shown in the comment below. This also leads to the point that in else closure, the program has to exit the current scope, by return, break, etc.
guard let x_val = x, x_val > 5 else {
return
}
//x_val available on this scope
One of the most direct ways to use optionals is the following:
Assuming xyz is of optional type, like Int? for example.
if let possXYZ = xyz {
// do something with possXYZ (the unwrapped value of xyz)
} else {
// do something now that we know xyz is .None
}
This way you can both test if xyz contains a value and if so, immediately work with that value.
With regards to your compiler error, the type UInt8 is not optional (note no '?') and therefore cannot be converted to nil. Make sure the variable you're working with is an optional before you treat it like one.
From swift programming guide
If Statements and Forced Unwrapping
You can use an if statement to find out whether an optional contains a
value. If an optional does have a value, it evaluates to true; if it
has no value at all, it evaluates to false.
So the best way to do this is
// swift > 3
if xyz != nil {}
and if you are using the xyz in if statement.Than you can unwrap xyz in if statement in constant variable .So you do not need to unwrap every place in if statement where xyz is used.
if let yourConstant = xyz {
//use youtConstant you do not need to unwrap `xyz`
}
This convention is suggested by apple and it will be followed by devlopers.
Although you must still either explicitly compare an optional with nil or use optional binding to additionally extract its value (i.e. optionals are not implicitly converted into Boolean values), it's worth noting that Swift 2 has added the guard statement to help avoid the pyramid of doom when working with multiple optional values.
In other words, your options now include explicitly checking for nil:
if xyz != nil {
// Do something with xyz
}
Optional binding:
if let xyz = xyz {
// Do something with xyz
// (Note that we can reuse the same variable name)
}
And guard statements:
guard let xyz = xyz else {
// Handle failure and then exit this code block
// e.g. by calling return, break, continue, or throw
return
}
// Do something with xyz, which is now guaranteed to be non-nil
Note how ordinary optional binding can lead to greater indentation when there is more than one optional value:
if let abc = abc {
if let xyz = xyz {
// Do something with abc and xyz
}
}
You can avoid this nesting with guard statements:
guard let abc = abc else {
// Handle failure and then exit this code block
return
}
guard let xyz = xyz else {
// Handle failure and then exit this code block
return
}
// Do something with abc and xyz
Swift 5 Protocol Extension
Here is an approach using protocol extension so that you can easily inline an optional nil check:
import Foundation
public extension Optional {
var isNil: Bool {
guard case Optional.none = self else {
return false
}
return true
}
var isSome: Bool {
return !self.isNil
}
}
Usage
var myValue: String?
if myValue.isNil {
// do something
}
if myValue.isSome {
// do something
}
One option that hasn't specifically been covered is using Swift's ignored value syntax:
if let _ = xyz {
// something that should only happen if xyz is not nil
}
I like this since checking for nil feels out of place in a modern language like Swift. I think the reason it feels out of place is that nil is basically a sentinel value. We've done away with sentinels pretty much everywhere else in modern programming so nil feels like it should go too.
Instead of if, ternary operator might come handy when you want to get a value based on whether something is nil:
func f(x: String?) -> String {
return x == nil ? "empty" : "non-empty"
}
Another approach besides using if or guard statements to do the optional binding is to extend Optional with:
extension Optional {
func ifValue(_ valueHandler: (Wrapped) -> Void) {
switch self {
case .some(let wrapped): valueHandler(wrapped)
default: break
}
}
}
ifValue receives a closure and calls it with the value as an argument when the optional is not nil. It is used this way:
var helloString: String? = "Hello, World!"
helloString.ifValue {
print($0) // prints "Hello, World!"
}
helloString = nil
helloString.ifValue {
print($0) // This code never runs
}
You should probably use an if or guard however as those are the most conventional (thus familiar) approaches used by Swift programmers.
Optional
Also you can use Nil-Coalescing Operator
The nil-coalescing operator (a ?? b) unwraps an optional a if it contains a value, or returns a default value b if a is nil. The expression a is always of an optional type. The expression b must match the type that is stored inside a.
let value = optionalValue ?? defaultValue
If optionalValue is nil, it automatically assigns value to defaultValue
Now you can do in swift the following thing which allows you to regain a little bit of the objective-c if nil else
if textfieldDate.text?.isEmpty ?? true {
}
var xyz : NSDictionary?
// case 1:
xyz = ["1":"one"]
// case 2: (empty dictionary)
xyz = NSDictionary()
// case 3: do nothing
if xyz { NSLog("xyz is not nil.") }
else { NSLog("xyz is nil.") }
This test worked as expected in all cases.
BTW, you do not need the brackets ().
If you have conditional and would like to unwrap and compare, how about taking advantage of the short-circuit evaluation of compound boolean expression as in
if xyz != nil && xyz! == "some non-nil value" {
}
Granted, this is not as readable as some of the other suggested posts, but gets the job done and somewhat succinct than the other suggested solutions.
If someone is also try to find to work with dictionaries and try to work with Optional(nil).
let example : [Int:Double?] = [2: 0.5]
let test = example[0]
You will end up with the type Double??.
To continue on your code, just use coalescing to get around it.
let example : [Int:Double?] = [2: 0.5]
let test = example[0] ?? nil
Now you just have Double?
This is totally logical, but I searched the wrong thing, maybe it helps someone else.
Since Swift 5.7:
if let xyz {
// Do something using `xyz` (`xyz` is not optional here)
} else {
// `xyz` was nil
}

Resources