What is the difference between "T?" and "T??" - swift

I understand the following code...
var dic1: Dictionary<String, String> = ["key" : "value"]
var str1: String? = dic1["key"]// key is not found => nil => String?
But I could not...
var dic2: Dictionary<String, String?> = ["key" : nil]
var str3: String?? = dic2["key"]// key is not found or set nil value => nil => why String??
What is the necessity of String?? and the difference of String? and String??.

The difference between String? and String?? is the following:
let s1 = Optional<String>() // String?
let s2 = Optional<Optional<String>>() // String??
Referencing your example:
The subscript of a Dictionary returns an optional type.
Therefore, because your value type in dic2 is a String?, you first have to unwrap the optional to determine whether the value exists for that key, then you have to unwrap your String?.
Here's an example to demonstrate:
if let optionalStringValue = dic2["key"] {
// A value exists for 'key'.
if let unwrappedStringValue = optionalString {
// In Swift 1.2 you could combine these two if let statements.
}
}

Related

Info.plist Dictionary to Dictionary of type Enum:String

I'm trying to take a dictionary from my Info.plist and save it as a Dictionary of type Enum: String
To better explain, I'm trying to convert the urlDict below to be a Dictionary of type but keep getting fatal error.
I can't figure out why
let enumDict = urlDict["keys"] as? Dictionary<URLKeys, String> does not work
The enum has a raw type of String and has a case for keyOne.
enum URLKeys: String {
case keyOne = "keyOne"
}
var keysDictionary = Dictionary<String, Any>()
keysDictionary["keyOne"] = "abc"
var urlDict = Dictionary<String, Any>()
urlDict["keys"] = keysDictionary
guard let enumDict = urlDict["keys"] as? Dictionary<URLKeys, String> else {
fatalError()
}
Use forEach and create a URLKeys for each key and cast each value to string
var enumDict:[URLKeys: String] = [:]
keysDictionary.forEach {
if let key = URLKeys(rawValue: $0.0), let value = $0.1 as? String {
enumDict[key] = value
}
}

Convert Int to String in Swift and remove optional wrapping?

I am attempting to convert Int? to a String and assign it to a label without including the optional text. I currently have:
struct Choice: Mappable{
var id: String?
var choice: String?
var questionId: String?
var correct: Bool?
var responses: Int?
init?(map: Map) {
}
mutating func mapping(map: Map) {
id <- map["id"]
questionId <- map["questionId"]
choice <- map["choice"]
correct <- map["correct"]
responses <- map["responses"]
}
}
In the class accessing it
var a:String? = String(describing: self.currentResult.choices?[0].responses)
print("\(a!)")
and the output is:
Optional(1)
How would I make it just output 1 and remove the optional text?
a is an Optional, so you need to unwrap it prior to applying a String by Int initializer to it. Also, b needn't really be an Optional in case you e.g. want to supply a default value for it for cases where a is nil.
let a: Int? = 1
let b = a.map(String.init) ?? "" // "" defaultvalue in case 'a' is nil
Or, in case the purpose is to assign the possibly existing and possibly String-convertable value of a onto the text property of an UILabel, you could assign a successful conversion to the label using optional binding:
let a: Int? = 1
if let newLabelText = a.map(String.init) {
self.label.text = newLabelText
}
Why don't?
let a : Int = 1
var b = "\(a)"
print(b)
so
$ swift
[ 9> let a : Int = 1
a: Int = 1
[ 10> var b = "\(a)"
b: String = "1"
[ 11> print(b)
1
By the way there are other options like this one
12> var c = a.description
c: String = "1"
13> print(c)
1

Cannot convert value of type 'String?' (Alamofire)

I map my class User with object mapper:
class User: Mappable{
private var _username: String! = nil
private var _password: String! = nil
private var _firstName: String! = nil
private var _lastName: String! = nil
//here are getters and setters(it takes too much space)
init(){
}
required init?(_ map: Map) {
}
func mapping(map: Map) {
username <- map["USERNAME"]
password <- map["PASSWORD"]
firstName <- map["FIRST_NAME"]
lastName <- map["LAST_NAME"]
}
}
And then i tried to make new user and put some values, map the whole object and send with Alamofire like this:
let userEmail = userEmailField.text!
let userPassword = userPasswordField.text!
let user = User()
user.username = userEmail
user.password = userPassword
let JSONString = Mapper().toJSONString(user, prettyPrint: true)
AlamofireService.alamofireService.makePostServiceRequest(URL_BASE, parameters: JSONString, resposeCallback: self)
I followed the instructions of libraries, but i get the error "Cannot convert value of type 'String?' to expected argument type '[String : AnyObject]'", why?
Alamofire request taking parameter in [String: AnyObject] format so you just need to pass dictionary as parameter. in your case you just need like:
let userEmail = userEmailField.text!
let userPassword = userPasswordField.text!
var dictParameter: Dictionary<String, AnyObject> = [:]
dictParameter["USERNAME"] = userEmail
dictParameter["PASSWORD"] = userPassword
And after that Just make request:
AlamofireService.alamofireService.makePostServiceRequest(URL_BASE, parameters: dictParameter, resposeCallback: self)
You don't need to covert your parameters to string, just pass parameters as dictionary to Alamofire.

Cast Protocol<> Any to String (or others)

I have a class called User()
class User {
var name: String?
var email: String?
var id: String?
var identification_number: String?
var phone_number: NSMutableArray?
var user_group: String?
var date: NSDate?
}
I want to get all of the variables in the class and their respective values. I am trying to use Mirror in this case.
func updateProfile(user: User) {
let mirror = Mirror(reflecting: user)
for child in mirror.children {
print("\(child.label!), \(child.value)")
}
}
My question is, how can I convert child.value to any other datatype, say String ?
I only got to find out that child.value belongs to the Protocol 'Any'
child.value has the Any type. Casting from Any to an optional poses some problems, fortunately Sandy Chapman gave a very nice solution in this post.
With his function, the code would look like this:
func castToOptional<T>(x: Any) -> T? {
return Mirror(reflecting: x).descendant("Some") as? T
}
func updateProfile(user: User) {
let mirror = Mirror(reflecting: user)
for child in mirror.children {
print("\(child.label!), \(child.value)")
if let stringVal = castToOptional(child.value) as String? {
print("Unwrapped a string: \(stringVal)")
} else if let stringVal = child.value as? String {
print("Found a non-optional string: \(stringVal)")
}
}
}
So if you're looking for strings, you need to look for both optional and non-optional ones. This applies to all types you need to check.
Create a protocol for extending Optional<Any> type to return it's non-optional-value:
private protocol AnyOptional {
var objectValue: Any? { get }
}
extension Optional: AnyOptional {
var objectValue: Any? {
switch self {
case .None:
return nil
case .Some(_):
return self! as Any
}
}
}
Thereafter you can use AnyOptional protocol as a type, and cast Any? objects to AnyOptional, thereafter allowing us to make use of the .objectValue property of AnyOptional
class User {
var name: String?
var email: String?
var id: String = "Default ID" // Lets try also with one non-optional
var identification_number: String?
var phone_number: NSMutableArray?
var user_group: String?
var date: NSDate?
}
var myUser = User()
myUser.name = "John"
myUser.phone_number = ["+44", "701 23 45 67"]
func updateProfile(user: User) {
let mirror = Mirror(reflecting: user)
for child in mirror.children {
let value : Any = (child.value as? AnyOptional)?.objectValue ?? child.value
switch(value) {
case let obj as String: print("String item: User.\(child.label!) = " + obj)
case let obj as NSMutableArray: print("NSMutableArray item: User.\(child.label!) = \(obj)")
case let obj as NSDate: print("NSDate item: User.\(child.label!) = \(obj)")
case _ : print("Non-initialized optional item: User.\(child.label!) = \(value)")
}
}
}
Which yields the following output
updateProfile(myUser)
/*
String item: User.name = John
Non-initialized optional item: User.email = nil
String item: User.id = Default ID
Non-initialized optional item: User.identification_number = nil
NSMutableArray item: User.phone_number = (
"+44",
"701 23 45 67"
)
Non-initialized optional item: User.user_group = nil
Non-initialized optional item: User.date = nil */
The benefit of using this solution is that it will "unwrap" optional non-nil values of child.value (without the "Optional(...)" padding) as well as values of child.value that are not optional, without the need of separate "unwrapping" for the two cases. In the switch case above, you can handle whatever non-nil property of the User object that you need to work with, not just as String but any of the types in your User class. The obj property in the switch case will be of the non-optional type of each of the non-nil properties of your class. The default case corresponds to optionals with value nil (not assigned).

swift How to cast from Int? to String

In Swift, i cant cast Int to String by:
var iString:Int = 100
var strString = String(iString)
But my variable in Int? , there for error: Cant invoke 'init' with type '#Ivalue Int?'
Example
let myString : String = "42"
let x : Int? = myString.toInt()
if (x != null) {
// Successfully converted String to Int
//And how do can i convert x to string???
}
You can use string interpolation.
let x = 100
let str = "\(x)"
if x is an optional you can use optional binding
var str = ""
if let v = x {
str = "\(v)"
}
println(str)
if you are sure that x will never be nil, you can do a forced unwrapping on an optional value.
var str = "\(x!)"
In a single statement you can try this
let str = x != nil ? "\(x!)" : ""
Based on #RealMae's comment, you can further shorten this code using the nil coalescing operator (??)
let str = x ?? ""
I like to create small extensions for this:
extension Int {
var stringValue:String {
return "\(self)"
}
}
This makes it possible to call optional ints, without having to unwrap and think about nil values:
var string = optionalInt?.stringValue
If you need a one-liner it can be achieved by:
let x: Int? = 10
x.flatMap { String($0) } // produces "10"
let y: Int? = nil
y.flatMap { String($0) } // produces nil
if you need a default value, you can simply go with
(y.flatMap { String($0) }) ?? ""
EDIT:
Even better without curly brackets:
y.flatMap(String.init)
Apple's flatMap(_:) Documentation
Optional Int -> Optional String:
If x: Int? (or Double? - doesn't matter)
var s = x.map({String($0)})
This will return String?
To get a String you can use :
var t = s ?? ""
Hope this helps
var a = 50
var str = String(describing: a)
Crude perhaps, but you could just do:
let int100 = 100
println(int100.description) //Prints 100
Sonrobby, I believe that "Int?" means an optional int. Basically, by my understanding, needs to be unwrapped.
So doing the following works fine:
let y: Int? = 42
let c = String(y!)
That "!" unwraps the variable. Hope this helps!
As rakeshbs mentioned, make sure the variable won't be nill.
You need to "unwrap" your optional in order to get to the real value inside of it as described here. You unwrap an option with "!". So, in your example, the code would be:
let myString : String = "42"
let x : Int? = myString.toInt()
if (x != null) {
// Successfully converted String to Int
// Convert x (an optional) to string by unwrapping
let myNewString = String(x!)
}
Or within that conditional, you could use string interpolation:
let myNewString = "\(x!)" // does the same thing as String(x!)
For preventing unsafe optional unwraps I use it like below as suggested by #AntiStrike12,
if let theString = someVariableThatIsAnInt {
theStringValue = String(theString!))
}
Swift 3:
var iString:Int = 100
var strString = String(iString)
extension String {
init(_ value:Int){/*Brings back String() casting which was removed in swift 3*/
self.init(describing:value)
}
}
This avoids littering your code with the verbose: String(describing:iString)
Bonus: Add similar init methods for commonly used types such as: Bool, CGFloat etc.
You can try this to convert Int? to string
let myString : String = "42"
let x : Int? = myString.toInt()
let newString = "\(x ?? 0)"
print(newString) // if x is nil then optional value will be "0"
If you want an empty string if it not set (nil)
extension Int? {
var stringValue:String {
return self == nil ? "" : "\(self!)"
}
}