How to unwrap Optional<Optional<T>> in Swift 1.2 - swift

Let's say we have String?? value. Optional of Optional may have 3 states:
let strOptOpt1: String?? = .Some(.Some("actual value"))
let strOptOpt2: String?? = .Some(.None)
let strOptOpt3: String?? = .None
To safely unwrap them to String, in Swift 1.1 we could:
if let str:String = strOptOpt? {
println(str)
}
else {
println("was nil") // `.Some(.None)` or `.None`
}
But it does not work anymore in Swift 1.2:
if let str:String = strOptOpt? {
// ^ [!] error: '?' must be followed by a call, member lookup, or subscript
At the moment, I think, I have to do like this:
if let strOpt = strOptOpt, str = strOpt {
println(str)
}
OR using switch:
switch strOptOpt {
case let .Some(.Some(str)):
println(str)
default:
println("was nil")
}
But, there must be simpler way to do this, I think. Anyone know that?

As of Swift 2, you can use if/case with a pattern, and x? as
a synonym for .Some(x):
if case let str?? = strOptOpt1 {
print(str)
} else {
print("was nil") // `.Some(.None)` or `.None`
}

For me, the best solution I found is using ?? operator in optional binding.
let strOptOpt: String?? = ...
if let str = strOptOpt ?? nil {
println(str) // "actual value"
}
Works for all these cases:
.Some(.Some("actual value"))
.Some(.None)
.None
But, if strOptOpt is String???, you should do:
let strOptOpt: String??? = ...
if let str = (strOptOpt ?? nil) ?? nil {
println(str)
}

I always get double optional in this situation
let field: ChangeField?? = json["field_id"].int.map{ ChangeField(rawValue: $0) }
Instead of map you can use flatMap
let field: ChangeField? = json["field_id"].int.flatMap{ ChangeField(rawValue: $0) }

Related

Does swift have standard (scope) functions like in Kotlin?

In Kotlin we have a list of standard (scope) functions (e.g. let, apply, run, etc)
Example of usage below
val str : String? = "123"
str?.let{ print(it) }
This makes the code looks more succinct without need to have if (str != null)
In swift, I code it as below
let str: String? = "123"
if str != nil { print(str!) }
I have to have if str != nil. Is there a let provided by default that I could use (without me writing my own)?
FYI, I'm new to Swift, and check around doesn't seems to find it.
if you like if, extend the functionality of Optional
extension Optional {
func `let`(do: (Wrapped)->()) {
guard let v = self else { return }
`do`(v)
}
}
var str: String? = "text"
str.let {
print( $0 ) // prints `text`
}
str = nil
str.let {
print( $0 ) // not executed if str == nil
}
You could use Optional.map :
let str1 : String? = "123"
str1.map { print($0) }
prints 123.
let str2 : String? = nil
str2.map { print($0) }
Doesn't print anything.
So if an optional is not nil, it is unwrapped and used as a parameter to the map closure. if not, the closure won't be called.
A more idiomatic approach in swift would be to use optional binding :
var str: String? = "123"
if let s = str {
print(s)
}
Apparently the Swift way of doing the nil check
let str: String? = "123"
if let strUnwrapped = str { print(strUnwrapped) }
And if really want to ensure it is not nil, use guard (thanks #CouchDeveloper for pointing out)
let str: String? = "123"
guard let strUnwrapped = str else { return }
I know this didn't explicitly answer the question of having scoping function or not, but it provides me my original intent of finding the Swift way of checking nil or non nil I was looking for like the let of Kotlin being used.

Is If let Evaluated Differently from If Statement?

Is if let kind of if statement, or is if let different?
Does the compiler treat if let and if statement differently?
if let is for unwrapping optional values.
if is for evaluating a condition
var example: String? = "rick"
if let name = example{
print(name) //name is the unwrapped version of example
}
If example is nil (no value), then the if let statement will fall through and the code inside of it will not run.
var example: Bool = true
if example{
print("Example is true")
} else{
print("Example is false")
}

Swift string from optional Double

Is there a shortcut to specify placeholder text when the value is nil in Swift?
Right now I do:
let myText:String!
if myDouble != nil{
myText = "\(myDouble!)"
}else{
myText = "Value not provided"
}
That works, but it's very annoying to have to do that all the time. Is there a way to do something like
let myText:String = "\(myDouble ?? "Value no provided")"
That fails because it wants a default Double value, but I really want a String value.
You can use map and nil-coalescing:
let myText = myDouble.map { String($0) } ?? "Value not provided"
If myDouble is nil, the result of map is nil and the result is the value after the ??.
If myDouble is not nil, the result is the output of the map which creates a string from the Double.
For more details, please see the documentation for the map function of the Optional enumeration in the Swift standard library.
It seems reasonable to do
let myDouble: Double? = Double(3.0)
let myText = myDouble?.description ?? "Value not provided"
If myDouble is nil, then myText is "Value not provided". If myDouble is not nil, it's assigned the string representation of the number.
I think good approach to this is to make Extension to optional where Double is the Wrapped element:
extension Optional where Wrapped == Double {
var stringValue: String {
guard let me = self else { return "No Value Provided" }
return "\(me)"
}
}
// Use it like this:
myDouble.stringValue
Another approach could be making your custom operator like this:
public func ??(rhd: Double?, lhd: String) -> String {
if let unwrapped = rhd {
return String(unwrapped)
} else {
return lhd
}
}
And now your line let myText:String = "\(myDouble ?? "Value no provided")" works.
Please let me now if you don' understand anything.
This should work:
let myText = myDouble != nil ? String(myDouble!) : "Value not provided"

unable to infer complex closure return type

unable to build swift project because of this error.
// showing error with inputs.flatmap
fileprivate func makeShippingAddressDictWith(inputs: [TextFieldData]) -> [String: String] {
var shippingDict: [String: String] = [:]
let _ = inputs.flatMap { input in
if let shippingFieldType = input.type as? ShippingDictKeyable.Type {
shippingDict[shippingFieldType.shippingDictKey] = input.text
}
return nil
}
// FIXME: these empty values are the result of a poorly designed request in GDKECommerce
shippingDict["email"] = ""
shippingDict["second_name"] = ""
shippingDict["suffix"] = ""
shippingDict["title"] = ""
shippingDict["salutation"] = ""
shippingDict["company_name"] = ""
return shippingDict
}
}
You could use .forEach instead of .flatMap. Then you would not have to worry about a return type that you are ignoring anyway (with let _ =).
Combining this with a filter would produce a cleaner functional statement if that's what you're after:
inputs.map{ ( $0.text, $0.type as? ShippingDictKeyable.Type) }
.filter{ $1 != nil }
.forEach{ shippingDict[$1!.shippingDictKey] = $0 }
// FIXME: these empty values are the result of a poorly designed request in GDKECommerce
let blankAttributes = ["email", "second_name", "suffix", "title", "salutation", "company_name"]
blankAttributes.forEach{ shippingDict[$0] = "" }
Or use a for loop as suggested by Hamish.
If performance is a factor, the compiler will produce faster code with the for loop than with map/filter/forEach.
Note that, if you want to go crazy with functional style, Swift 4 will let you return the whole dictionary in a single line:
return [String:String]( uniqueKeysWithValues:
inputs.map{ ($0.type as? ShippingDictKeyable.Type, $0.text) }
.filter{ $0.0 != nil }
.map{($0!.shippingDictKey,$1)}
+ ["email", "second_name", "suffix", "title", "salutation", "company_name"]
.map{($0,"")}
)
This may only work in the playground though cause real projects tend to complain about expressions being too complex more often.

swift reflection causes impossible nil value for any

I'm trying to use swift reflection to check for changes in objects so I can send only changed properties up to the server. Some of my properties are optional. To compare those values, I need to unwrap them but, of course, you can ONLY unwrap actual values, not nil values. So, I need to check if one of the values is nil before I compare them.
In my playground, I tried the following:
import UIKit
class myClass
{
var fieldOne:String?
var fieldTwo:Int?
var fieldThree:Float?
}
var oneMyClass = myClass()
oneMyClass.fieldOne = "blah"
oneMyClass.fieldThree = 3.5
var oneOtherClass = myClass()
oneOtherClass.fieldOne = "stuff"
oneOtherClass.fieldTwo = 3
let aMirror = Mirror(reflecting: oneMyClass)
let bMirror = Mirror(reflecting: oneOtherClass)
for thing in aMirror.children
{
for thing2 in bMirror.children
{
if thing.label! == thing2.label!
{
print("property: \(thing.label!)")
print("before: \(thing.value)")
print("after: \(thing2.value)")
print("")
//let myTest = thing.value == nil ? "nil" : "not nil"
}
}
}
And it generates the following output:
property: fieldOne
before: Optional("blah")
after: Optional("stuff")
property: fieldTwo
before: nil
after: Optional(3)
property: fieldThree
before: Optional(3.5)
after: nil
As you can see, the expected properties are displayed as "nil". However, if you uncomment the let statement, you get an error stating:
playground52.swift:37:38: error: value of type 'Any' (aka 'protocol<>') can never be nil, comparison isn't allowed
And yet, we know from the output that it IS nil. How can this be and what can I do about it?
Based on this answer, I recommend using if case Optional<Any>.some(_).
For example:
aMirror.children.forEach {
guard let propertyName = $0.label else { return }
if case Optional<Any>.some(_) = $0.value {
print("property: \(propertyName) is not nil")
} else {
print("property: \(propertyName) is nil")
}
}
Thats look like some sort of bug. Look at that
let x = childMirror.value == nil ? "Nil" : "Not Nil" //dont compile.
let y = { (value:Any?) in
return value == nil ? "Nil" : "Not Nil"
}
let z = y(childMirror.value) //compile, but doesn't evaluate.
I guess the problem is because Any can store a Optional, but can't be wrapped around one. Try this:
func getValue(unknownValue:Any) -> Any {
let value = Mirror(reflecting: unknownValue)
if value.displayStyle != .Optional || value.children.count != 0 {
return "Not Nil"
} else {
return "Nil"
}
}