I came across these lines of code for a simple calculator app.
func processOperation (operation: Operation) {
if currentOperation != Operation.Empty {
if runningNumber != "" {
rightValStr = runningNumber
runningNumber = ""
if currentOperation == Operation.Multiply {
result = "\(Double(leftValStr)! * Double(rightValStr)!)"
} else if currentOperation == Operation.Divide {
result = "\(Double(leftValStr)! / Double(rightValStr)!)"
} else if currentOperation == Operation.Subtract {
result = "\(Double(leftValStr)! - Double(rightValStr)!)"
} else if currentOperation == Operation.Add {
result = "\(Double(leftValStr)! + Double(rightValStr)!)"
}
leftValStr is declared as var leftValStr = ""
rightValStr is also declared as var rightValStr =""
I am wondering what the purpose of using "!" in \(Double(leftValStr)! / Double(rightValStr)!) is for?
From what I know, "!" is for unwrapping optional. leftValStr and rightValStr here are not declared as Optional so why do we have to unwrap them?
Even if leftValStr and rightValStr are not optionals, you are force unwrapping Double(leftValStr) and Double(rightValStr) and the result of initializing Double with a String value can be nil.
For example, you can't initialize a Double with a stackoverflow String.
If you'd like to make sure that this conversion result is correct you can use an if let to avoid force unwrapping, for example:
if let leftValDouble = Double(leftValStr) {
// do your code
} else {
// handle error
}
Please remember that if you force unwrap a nil value, your code will crash.
The Double initializer that you are using is a failable initializer, i.e. it might create a Double or return nil.
Example,
Double("3"), here "3" can be converted into Double, so it returns an optional Double value corresponding to 3.
Double("abc"), here "abc" cannot be converted into Double, so it returns nil in this case.
In your code, you are using Double(""), which also cannot be converted into Double, hence it returns nil.
Now, when you force unwrap a nil value, it will result in runtime exception.
Hence, Double(leftValStr)! results in runtime exception.
Trying to use ! to access a nonexistent optional value triggers a
runtime error. Always make sure that an optional contains a non-nil
value before using ! to force-unwrap its value.
Related
I'm new to Swift and I'm wondering if there's a 'short hand' form of assigning Optional values to non-optional values without doing if nil check.
For example if I've got an Optional closure:
var onTap: (() -> Void)?
I can later on call this via
onTap?()
The ? let's me skip the nil check and force unwrap.
But I'm curious if something exists for values that are not clousre. For example
var oldTransform: CGAffineTransform?
var someTransform: CGAffineTransform //non optional
and later on, I decide to assign oldTransform to someTransform I have to
if (oldTransform != nil) {
someTransform = oldTransform!
}
Is there a pattern that's less verbose to do the above (kinda of like the ?)?
Yes, of course. You could use if let as below:
if let unwrappedOldTransForm = oldTransform {
someTransform = unwrappedOldTransForm
}
When you check with if let, it will unwrap the value for you and check if it can set the value of oldTransform to unwrappedOldTransForm. If the value is nil you will be able to handle the error by adding an else condition as below:
if let unwrappedOldTransForm = oldTransform {
someTransform = unwrappedOldTransForm
} else {
// handle if oldTransform is nil
}
In the case of a function, as you know, "calling" a nil function (like onTap?()) has no effect - but for an assignment to a non-optional type you need to supply a definite non-optional value. For that you can use the nil-coalescing operator ?? like so:
var optionalString: String?
// ... maybe set optionalString ...
var realString: String = optionalString ?? "<some default value>"
In your example, it would be
someTransform = oldTransform ?? CGAffineTransform(...) // some default - say Identity
or even, as commentator #user28434 suggests
someTransform = oldTransform ?? someTransform // assuming someTransform already initialised
which will only change someTranform if oldTransform isn't nil.
In each case, the left hand operand of ?? will be assigned if is non-nil, otherwise the right hand side operand will be assigned.
I've read Non-optional shown as optional on print but that doesn't help my question.
I'm returning a Integer, but once it's printing it's being printed as optional. Why?
I'm trying to solve a code challenge. The goal is to:
Write an extension for collections of integers that returns the number
of times a specific digit appears in any of its numbers.
Here is my implementation:
extension Collection where Iterator.Element == Int {
func challenge37(count character : Character) -> Int?{
guard nil != Int(String(character)) else{
print("character wasn't an integer")
return nil
}
var counts : [Int] = []
for item in self{
var counter = 0
let stringInt = String(describing: item)
for currentCharacter in stringInt.characters{
if character == currentCharacter{
counter += 1
}
}
counts.append(counter)
}
guard let min = counts.min() else{
print("no min")
return nil
}
return min
}
}
As you can see here I'm printing it:
print([5,15,512,522].challenge37(count: "5")) // Optional(1)
Inside the function your returning an Int. However the actual signature of your method is Int? meaning it is in fact an optional and you got it wrong!
Basically your method signature is correct. But when you call the function you're getting an optional as the response and must unwrap it.
print([5,15,512,522].challenge37(count: "5")!) // 1
Additionally had you paid close attention you would have noticed that Xcode must gave you a warning (and solutions to solve it)
Expression implicitly coerced from Int? to Any
Xcode gave you the warning because it found out that you're attempting to print an optional and knows that's usually unwanted. Obviously its solution is to unwrap it either through force unwrap or defaulting.
Dears
I have this case where chatId is a property of type Int
let StringMessage = String(self.listingChat?.messages.last?.chatId)
When I debug I find that StringMessage is returning Optional(15) Which means it is unwrapped. But at the same time XCode does not allow me to put any bangs (!) to unwrap it. So I am stuck with Unwrapped Variable. I know its noob question but it I really cant get it. Your help is appreciated.
Thank you
It depends on what you want the default value to be.
Assuming you want the default value to be an empty string (""), You could create a function or a method to handle it.
func stringFromChatId(chatId: Int?) -> String {
if let chatId = chatId {
return String(chatId)
} else {
return ""
}
}
let stringMessage = stringFromChatId(self.listingChat?.messages.last?.chatId)
Or you could handle it with a closure.
let stringMessage = { $0 != nil ? String($0!) : "" }(self.listingChat?.messages.last?.chatId)
If you don't mind crashing if self.listingChat?.messages.last?.chatId is nil, then you should be able to directly unwrap it.
let StringMessage = String((self.listingChat?.messages.last?.chatId)!)
or with a closure
let stringMessage = { String($0!) }(self.listingChat?.messages.last?.chatId)
Update
Assuming chatId is an Int and not an Optional<Int> (AKA Int?) I missed the most obvious unwrap answer. Sorry, I was tired last night.
let StringMessage = String(self.listingChat!.messages.last!.chatId)
Force unwrap all the optionals along the way.
Optionals have a very nice method called map (unrelated to map for Arrays) which returns nil if the variable is nil, otherwise it calls a function on the (non-nil) value. Combined with a guard-let, you get very concise code. (I've changed the case of stringMessage because variables should begin with a lower-case letter.)
guard let stringMessage = self.listingChat?.messages.last?.chatId.map { String($0) } else {
// Do failure
}
// Success. stringMessage is of type String, not String?
I think:
let StringMessage = String(self.listingChat?.messages.last?.chatId)!
I'm getting errors when concatenating string:
let likeKey = "like-" + foodPhotoObjects[indexPath.row].objectId
Error
binary operator '+' cannot be applied to operands of type 'String' and 'String?!'
So, you have an implicitly-wrapped optional of an optional string, something like this:
struct Thing {
let objectId: String?!
}
let foodPhotoObjects: [Thing] = [Thing(objectId: "2")]
With any doubly-wrapped optional, to get to the object inside you’d need to unwrap it twice:
// first unwrap the String?! into a String?
if let outer = foodPhotoObjects[0].objectId,
// then unwrap that String? into a String
inner = outer {
// inner is now a String
println("like-\(inner)")
}
The key here is even though the outer optional is implicit (i.e. ! rather than ?), you can still unwrap implicit optionals using if let, so the implicitness is irrelevant when doing this.
An alternative way of handling this kind of thing, rather than if-let, is to use map:
let concatedString = foodPhotoObjects[indexPath.row].objectId.map {
"like-" + $0
} ?? ""
map on an optional means: if the optional contains a value, change the value using this function and return that as an optional, otherwise return nil. So, unwrap the String? and prepend “like” to it.
?? on an optional means: if the preceding value is nil, replace it with the default on the right-hand side (the empty string), otherwise unwrap it and return that (i.e. the value we just mapped).
Now for the tricky part: because the value we’re calling map on is an implicit optional, it will be implicitly unwrapped – that is, the map is being called on the inner String? rather than on the String?!. This is unlike the case with if let where that was run on the implicit optional first, then the inner optional.
As with all implicit optionals, there’s a risk that they might actually be nil in which case your code would blow up, like so:
let explode = Thing(objectId: nil)
// the next line will generate fatal error: unexpectedly
// found nil while unwrapping an Optional value
explode.objectId.map { "like-" + $0 }
If this is a concern, you could guard against it with some optional chaining:
// note, ? after objectId
let concatedString = foodPhotoObjects[indexPath.row].objectId?.map {
"like-" + $0
} ?? ""
This snippet could win a prize for most optional-handling techniques crammed into a single statement… but it should do what you need.
Swift does not do implicit conversion, even if both are of same type and one of them is of optional type.
Try this.
var concatedString = ""
if let foodphoto = foodPhotoObjects[indexPath.row].objectId as? String {
concatedString = "like-" + foodphoto
}
I have a variable
var a: [AnyObject? -> Void]
and I am adding data in to it by append method. Now I want to check if the variable is nil or not. I tried using [] but not working and also tried "", this also not working, can anyone tell what is the meaning of this variable and how to check if it is nil.
As far as I understand, var a is an Array of functions that take an optional Object of any type, and return void. So these functions's parameter IS optional, but the Array itself isn't : it cannot be nil, or it would be declared [AnyObject? -> Void]? , no?
EDIT : if, nevertheless, you declared this a as an optional (but WHY would you do that ?) - adding a ? - you check an optional existence with if let :
if let b = a {
// a not nil, do some stuff
} else {
// a is null
}
If you just want to check if the array is empty, use isEmpty method from Swift Array
Update: Xcode 7.3 Swift 2.2
If you want to check if a variable is nil you should use if let to unwrap if for you. There is no need to create a second var.
let str = "123"
var a = Int(str)
if let a = a {
print(a)
}
Or
if let a = Int(str) {
print(a)
}
In Swift, nil is not a pointer—it is the absence of a value of a certain type. Optionals of any type can be set to nil, not just object types.
So, You can check it with below code:
let possibleNumber = "123"
let convertedNumber = possibleNumber.toInt()
if convertedNumber != nil {
println("convertedNumber contains some integer value.")
}
// prints "convertedNumber contains some integer value."
Please refer this about nil for more information.
In Swift 3.0
if let imageURL = dictObj["list_image"] as? String {
print(imageURL)
}
You can use if let. if let is a special structure in Swift that allows you to check if an Optional holds a value, and in case it does – do something with the unwrapped value.
var a:Int=0
if let b=a{
println(a)
} else {
println("Value - nil")
}
But for Strings you can also use .isEmpty() If you have initialized it to "".
var str:String=""
if !str.isEmpty(){
println(str)
}
For me none of the above solutions worked when I was using an AVFoundation object.
I would get Type 'AVCaptureDeviceInput does not conform to protocol 'BooleanType' when I tried if (audioDeviceInput) and I would get Binary operator '!=' cannot be applied to operands of type 'AVCaptureDeviceInput' and 'nil'.
Solution in my situation
if (audioDeviceInput.isEqual(nil))
nil is a pointer like any other and can be referenced as such, which is why this works.