Swift Optionals - Inconsistency? - ios

I'm slightly confused - I thought I understood Optionals and on the Apple dev forums Chris L, mentioned a work around to the immutable Optional issue was to create a class wrapper for the optional value type. -link!
However take this example with UIWindow (an optional class type with various properties)
The properties still don't seem mutable with optional chaining!
var window: UIWindow?
//this works (force unwrap)
self.window!.backgroundColor = UIColor.greenColor()
//this optional chain doesn't work... why not? Isn't this just a safer version of the above?
self.window?.backgroundColor = UIColor.redColor()
This seems to be fixed in beta 5!

update for Xcode beta 5
the originally asked issue has been resolved in Xcode beta5, that may invalidate this answer.
original anwer
that may request further explanation, why it is definitely not inconsistent behaviour but is simple invalid.
the optional value has to be always of the right side of the actual operand, and it cannot be on the left side of it.
see that logic via two simple examples:
example 1
in case of this line of code:
self.window?.backgroundColor = UIColor.redColor()
< LEFT ^ RIGHT >
the optional is on the left side which would mean the left side could be nil therefore the following operand would appear here in runtime:
nil = UIColor.redColor()
which is clearly invalid on every level without any further or complex explanation – a nil cannot be assigned to something else, that is why the compiler does not allow it.
NOTE: you may assume that the logical behaviour would be like this in the case of self.window = nil:
nil.backgroundColor = UIColor.redColor()
but the documentation about Optional Chaining highlights a very important behaviour which explains why that is not happening at all:
Multiple queries can be chained together, and the entire chain fails gracefully if any link in the chain is nil.
emphasis is on the word "entire", thus that is why the left side will be nil = ... and not nil.backgroundColor = ... as you'd expect after Objective-C.
example 2
the other answer highligths another idea of how it can be solved:
self.window?.setBackgroundColor(UIColor.redColor())
why is that working? would it not be a little inconsistency here? definitely not.
the actual optional is on the right side of the operand here, because that line is equal to this line, however we are not bothered to get the void in practice at all.
let result: Void! = self.window?.setBackgroundColor(UIColor.redColor())
< LEFT ^ RIGHT >
as you see there is not any inconsistency at all here, because in the case of self.window = nil that line would be equal to this one in runtime (please see the explanation above):
let result: Void! = nil
and that would be a completely legal operand.
the logic is simple, the optional must be always at the right side of the operand (or operator), on the left side it can be non-optional value only.

Optional chaining works for reading values (return value or nil), it works for calling methods (call this method or do nothing) but doesn't work for assignments.
I believe this is by design but I don't see a reason why it is so because this is essentially the same as:
extension UIWindow {
func setBackgroundColor(color: UIColor) {
self.backgroundColor = color
}
}
self.window?.setBackgroundColor(UIColor.redColor())
and that works without problems. You can report a bug or ask on the dev forums.
I believe optional chaining here is logically inconsistent.
Your example from dev forums doesn't have anything to do with this problem since that problem is about value types.

Related

Why does Swift 2 favor forced unwrap over optionals?

I no longer see Xcode complaining that certain things need optionals (the "?"). Now it is always forced unwrapped (the bang "!"). Is there any reason to use optionals anymore when we now have forced unwrap?
I don't really know what you mean when you write that you no longer see Xcode complaining that "certain things need optionals. Now it is always forced unwrapped". These two sentences contradict eachother:
You may have non-optional variables as much as you wish, but optional can really nice once you get to know all the benefits of using them.
If you have a property that is not an optional, then it won't need, by definition, any unwrapping.
Perhaps what you ment was that Xcode seemingly complains less often when you actually do force unwrap optionals, or, as a bad habit of Xcode, prompts you to force unwrap things to avoid compile time errors. This is generally because Xcode cannot know at compile time that you just wrote code that will break your app at runtime.
Xcode may seemingly at times have only one single purpose with its "smart hints": namely to absolve compile time errors. If you try to assign the value of a String? type (optional String) to String type, Xcode will prompt you with a compiler error and ask if you ment to add the forced unwrapping operator !. Smart Xcode, you say? Meh, Xcode is good for many things, but deciding how you unwrap your optionals is, not yet anyway, one of them. So even with Xcode prompting you for all kinds of things: if you can use optional chaining, do.
There might be exception, of course. For the controller part of the MVC design pardigm, you usually use the as! operator to do "forced conversion" (casting), with Xcode sometimes telling you to explicitly to use as! instead of as, e.g. "Did you mean as! ... ?". In these situations, Xcode can sometimes actually know what its doing and infer that you are trying to cast, as an example, a custom UIViewController class instance to type UIViewController, i.e., to it's parent class. I'd say that this is perhaps one of the few times I use the "forced" marker ! without go-arounds; forced conversion to types I know with 100% certainty to be castable.
The as! operator
But let's leave the subject of type conversion/casting and move on to optional types, wrapping, and optional chaining, in general.
Generally, you should avoid force unwrapping unless you explicitly knows that the entity you unwrap will be non-nil. For general class properties, variables and so on, given that you state this question the way you do, I'll give your the following advice:
If you can use conditional unwrapping (if-let, guard-let, nil
coalescing operator ??), then don't use forced unwrapping (!).
Below follows an example of the dangers of forced unwrapping. You can treat the first if clause (if arc4random...) as any smaller or larger segment of some program you've written with imperative programming techniques: we don't really know in detail just how 'name' will turn out until runtime, and our compiler can't really help us out here.
var name : String?
/* 'name' might or might not have a non-nil
value after this if clause */
if arc4random_uniform(2) < 1 {
name = "David"
}
/* Well-defined: us an if-let clause to try to unwrap your optional */
if let a = name {
print("Hello world "+a)
/* Very well-behaved, we did a safe
unwrap of 'name', if not nil, to constant a */
print("Hello world "+name!)
/* Well... In this scope, we know that name is,
for a fact, not nil. So here, a force unwrap
is ok (but not needed). */
}
let reallyGiveMeThatNameDammit = name!
/* NOT well-defined. We won't spot this at compile time, but
if 'name' is nil at runtime, we'll encounte a runtime error */
I recommend you to read up on optional chaining, a key subject in Swift.
Swift Language Guide - Optional Chaining
do you mean that cocoa stuff? do you mean implicitly unwrapped?
protocol AnyObject { ... }
The protocol to which all classes implicitly conform.
When used as a concrete type, all known #objc methods and properties are available, as implicitly-unwrapped-optional methods and properties respectively, on each instance of AnyObject. For example:
class C {
#objc func getCValue() -> Int { return 42 }
}
// If x has a method #objc getValue()->Int, call it and
// return the result. Otherwise, return nil.
func getCValue1(x: AnyObject) -> Int? {
if let f: ()->Int = x.getCValue { // <===
return f()
}
return nil
}
// A more idiomatic implementation using "optional chaining"
func getCValue2(x: AnyObject) -> Int? {
return x.getCValue?() // <===
}
// An implementation that assumes the required method is present
func getCValue3(x: AnyObject) -> Int { // <===
return x.getCValue() // x.getCValue is implicitly unwrapped. // <===
}

Stanford calculator app crashes with error "unexpectedly found nil"

I'm new to programming and I've started taking the stanford course on iTunes U for making an iPhone 8 app. They're using Xcode 6 and Swift 1 while I'm in El Capitan using Xcode 7 and Swift 2. I've found a few differences in code that Xcode has been able to pick up on and help me correct ("println" is now "print" for example), but I'm getting tripped up on one particular part of the code:
var displayValue: Double {
get {
return NSNumberFormatter().numberFromString(display.text!)!.doubleValue
}
set {
display.text = "\(newValue)"
userIsInTheMiddleOfTypingANumber = false
}
}
I've double checked several times to make sure this is exactly how the teacher wrote it. His built correctly and functioned correctly, while mine builds correctly, but shows this fatal error when I try to operate it, "unexpectedly found nil while unwrapping an Optional value" (see screenshot for all the details).
Screenshot of the error
I've been looking around the internet and found a few similar examples, including one on this site (Stanford Calculator app keeps crashing), but after trying everything that was suggested I concluded that something must be unique in my system or I'm operating in a new Xcode/Swift environment than the others that had this problem. None of the solutions have resolved the problem, and all of them added errors of their own.
In responding to someone else's question someone suggested that we use this code to ensure that if "nil" is returned by "display" that it will provide "0" instead:
return (NSNumberFormatter().numberFromString(display.text) as? Double) ?? 0
I tried this, but it only gave me more errors, some seem to be related to Swift 2 (it required a comma after double, wanted me to unwrap display.text, and complained that there was an expected expression missing—maybe the suggested code was good in Swift 1??).
I've double checked several times to make sure this is exactly how the teacher wrote it. His built correctly and functioned correctly, while mine builds correctly, but shows this fatal error when I try to operate it, "unexpectedly found nil while unwrapping an Optional value"
I suspect that display is an IBOutlet property that needs to be connected to something in the user interface, probably a text field. If it's not connected, then even though your code is exactly the same, you'll get nil when you try to use its text property, and unwrapping that will cause the error you're seeing.
Whether or not the advice above actually solves your problem, what you really need to do is to set a breakpoint a line or two before the spot where the crash occurs and step through the code. Look at the variables involved and figure out where that nil value is coming from. You can work backward from there and figure out why the thing that you expect not to be nil is, in fact, nil. Learning to work that way will help you work out these kinds of problems when they occur (and they will occur again).
Not sure if you've found the answer or not by now, but I ran into a similar problem this morning and thought I'd share what I found.
While debugging, I entered two console logs to a simplified version of my operate like so:
case "x": if operandStack.count >= 2 {
print(" display before popping is: \(display.text!) ")
displayValue = operandStack.removeLast() * operandStack.removeLast()
print(" display after popping is: \(display.text!) ")
enter()
}
Display after popping came up as "newValue". I couldn't figure out what that meant at first, but realized that my issue is the setter. newValue is an optional that should be unwrapped i.e. "(newValue)!"
P.S. I opted to return:
return (display.text! as NSString).doubleValue
in my get.
Also, since newValue is unwrapped, keep in mind it will crash if display is set to nil.

Swift 2.0 Subscript issues with Dictionary

I've looked at the other questions on here about subscripting with dictionaries and I didn't see anything that quite fit what my scenario is. It may be that I'm still too new to Swift to realize it but in any case here is my scenario. I'm getting the typical can't "Subscript" dictionary with type string. I've seen the posts on here about it being an optional and needing to unwrap it however when I try that, Xcode suggests that I remove the !, so I do that, then I get the subscript error.
I've watched tons of tutorials on swift development and a lot of them use playgrounds and I never remembered seeing anyone have to do this in any of the tutorials. So I tried the same thing in a playground and it worked.
Here is what I have in the ViewController that DOESN'T work.
var validFields:Dictionary = ["loanBalanceInput":false,"cashOutInput":false,"appraisedValueInput":false,"interestRateInput":false]
func validationSuccess(sender:UITextField){
sender.backgroundColor = green
switch sender {
case loanBalanceInput:
validFields["loanBalanceInput"] = true
break
default:
break
}
}
What I've done is create a dictionary of strings that refer to textfields and their validation status to track whether or not they have been validated. The concept is that when everything in the dictionary is true, I can activate the calculate button.
However I get the "cannot subscript a value of type dictionary with an index of type string" error... However this code in a playground works...
var validatedFields:Dictionary = ["loanBalanceInput":false,"cashOutInput":false,"appraisedValueInput":false,"interestRateInput":false]
validatedFields["loanBalanceInput"]
validatedFields["loanBalanceInput"] = true
I don't understand what's going on here. Is it because this is an optional?
#IBOutlet weak var loanBalanceInput: UITextField!
I'm not unwrapping it in my switch? I'm not trying to get at the value of loanBalanceInput though, I'm just checking to see if it was the sender.
Normally a Swift Dictionary declaration needs also the type of the containing keys and values like
var validFields: Dictionary<String,Bool> = [" ...
but as the compiler can infer the type just delete the annotation.

How to debug 'fatal error: unexpectedly found nil while unwrapping an Optional value'

There are a lot of questions on Stack Overflow related to this error. I’ve read some excellent posts on how Optionals work and this error in particular. However, I haven’t found any information about the best way to figure out which value is being set to nil and causing the error in the first place.
Are there any good debugging techniques to find out which Optional is causing this error?
Here's at least half an answer (would the other respondents please read the question first!): Use the simulator instead of an actual iOS device.
The debugger seems to be pretty good at pointing to the line with the maltreated optional that's causing the trouble... unless you are like me, choosing to run the code on an iOS device directly from time to time. In the latter case, the debugger lands me right in the middle of some assembler code with no sensible stack trace. Switching back to the simulator gives the exact line of code at fault.
You Xcode does not crash at the incorrect line of code?
This does not response to the question but it's important to note:
When you are not sure about an optional variable, you have to verify if it contains value or not, by using a pattern like this:
var myOptional : String?
if let aString = myOptional {
//do your work with aString.
}
What basically optional value is "?" when you place ? after a datatype that is optional while if it is unwrapped and a nil appears theres no error but it you place "!" exclamation mark after datatype then if it unwrap the variable and nil appears then there's crash or error so often use optional as
var myVariable : DataType ? = DataType()
or
var myVariable : DataType ? = nil
or
var myVariable : DataType ? = value
An optional in Swift is a variable that can hold either a value or no value. Optionals are written by appending a ? to the type:
var myOptionalString:String? = "Hello"
Some places optionals are useful:
When a property can be there or not there, like middleName or spouse
in a Person class
When a method can return a value or nothing, like
searching for a match in an array
When a method can return either a result or get an error and
return nothing
Delegate properties (which don't always have to be set)
For weak properties in classes. The thing they point to can
be set to nil
For a large resource that might have to be released to
reclaim memory
https://medium.com/#rrridges/swift-optionals-a10dcfd8aab5

Swift good coding practice: If statement with optional type Bool

So I've been developing an app in Swift, and today I spent nearly an hour debugging a problem that turned out to be completely unexpected. It all resulted from the code below.
if (hero.isAI) { //isAI is a Bool
}
The problem was that this if statement ALWAYS returned true. So I thought that maybe I was setting isAI to true somewhere but in the end I realized that I declared isAI as an optional type as shown below.
var isAI: Bool!
when it should have been
var isAI: Bool
This resulted in the if-statement not checking if isAI was true, but instead checking if it contained a value.
So to be safe now I make sure to write my if-statments like this
if (hero.isAI == true) { //isAI is a Bool
}
So my question is, what are my options to avoid this problem in the future? (this problem seems extremely dangerous, especially when working on a team on a large project).
Should I always write my if-statment explicitly, should I just avoid the optional type for Bools altogether?
Note that I did not have this problem in Xcode Beta 2. This problem came about when I upgraded to Xcode beta 3. I think because in Beta 2 Apple handled implicitly unwrapped Bool in an if-statement by checking its value rather than checking if it contains a value.
Lastly, below is an example of which if-statements run given an optional Bool to better help people understand the problem.
let myBool: Bool! = false
if (myBool) {
//Runs
}
if (myBool!) {
//Won't Run
}
if (!myBool) {
//Runs
}
if (myBool == true) {
//Won't Run
}
This is a known issue that is being tracked on the SwiftInFlux repo, which includes this quote from Chris Lattner on the Apple developer forums.
This problem exists with any optional of something that conforms to
the LogicValue protocol (e.g. nested optionals, optional of bool,
etc). We consider it serious issue that needs to be fixed for 1.0 and
have some ideas, but haven't settled on a solution yet.
So, this issue doesn't just effect optional Bools, but any optional type that conforms to the LogicValue protocol (defined as).
protocol LogicValue {
func getLogicValue() -> Bool
}
Anyway as far as recommendations on how to work around this go, it's hard to recommend any one specific solution considering that Apple hasn't given an indication of how they intend to solve this in the future, but I would imagine that continuing to explicitly check the value of the Bool would be the way to go.
if (hero.isAI == true) {
// stuff
}
In fact, after some further reading, the quote listed above continues to read:
For this common case, the simplest answer would be to produce a
warning for "if x" and require someone to explictly write "if x !=
nil" or "if x == true" to make it explicit what they want.
my advice is to use this nice coalescing ??
if textfieldDate.text?.isEmpty ?? true {
// the text is either nil or empty but its all we want to know
}
If the bool is part if Core Data (aka NSNumber), you should do it like this.
if (isHero.isAI?.boolValue != nil)
Regards

Resources