What is the purpose of calling text.flatMap(URL.init)? - ios

What is the purpose of calling text.flatMap(URL.init) in the following:
guard let url = someUITextField.text.flatMap(URL.init) else {
return true
}
someUITextField.text is assumed to have a URL string that a user entered.

text is an optional and URL(init) returns also an optional. The result is a double optional URL??
flatMap first transforms the String? to URL?? then it removes one ? to be able to if let the expression.
Please read What’s the difference between map(), flatMap() and compactMap()? on hackingwithswift for details.

Related

Converting string (Contains json string) to NSURL in swift

I have PAI its Implemented in .NET.
one of the web service url is like this
http://123.321.33/UploadCitizenImage?jsonString={\"Mobile\":\"12345678\", \"fileName\":\"7661832460_05072018.png\"}
while converting above string to URL in swift, app going crash.
for more info check this
The URL(string:) initializer returns an optional since the parsing of the string may fail. In that case, nil is returned. That's exactly what's happening here since the string you are providing is not a valid URL: there are several characters in the query that are not allowed there and need to be replaced: { as %7B, " as %22, space as %20 and } as %7D.
So the initializer returns nil. Next thing you do is force unwrap via the ! operator. But force-unwrapping a nil is illegal and is why you get the crash.
If you want to create an URL, please look into the URLComponents class which does all the necessary escaping for you so you don't need to care about it. The queryItems property is of particular interest for you, it's an array of URLQueryItem.
Please do something like that,
let jsonString = "jsonString={\"Mobile\":\"12345678\", \"fileName\":\"7661832460_05072018.png\"}" as String
let urlEncoadedJson = jsonString.addingPercentEncoding(withAllowedCharacters:.urlHostAllowed)
let urls = NSURL(string:"http://123.321.33/UploadCitizenImage?\(urlEncoadedJson ?? "")")
First convert your json into encodedJson then add into your url.
Do let me know if there is some issue.
You can try this,
let string = "http://123.321.33/UploadCitizenImage?jsonString={\"Mobile\":\"12345678\", \"fileName\":\"7661832460_05072018.png\"}"
let escapedString = string.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
let url = URL(string: escapedString!)!
print(url)
Output will be like this,
http://123.321.33/UploadCitizenImage?jsonString=%7B%22Mobile%22:%2212345678%22,%20%22fileName%22:%227661832460_05072018.png%22%7D

strange optional behaviour in Swift

I have created my own class in Swift as below.
class Product: NSObject {
var product_id:Int?
var product_number:String?
var product_price:Float?
var product_descrption:String?
}
Now i am setting value in each property like this
let p=Product()
p.product_id=1
p.product_price=220.22
p.productdescrption="Some description"
p.product_number="W2_23_233"
But when i get the value from price then for price i get value like "Optional 220.22" But i don't get appended word "Optional" in description".So to resolve this i added "!" for unwrapping the value of float but i did not have to do this for String please tell why this is happening?
If you are printing any of these values should say Optional(...). If you are assigning the values to a label, that will not include the Optional(...), The reason that it shows Optional(...) when you print the value using print(), is just to show you its an optional. For safety, instead of using the !, try using if lets.
An example with your code,
if let id = p.product_id {
print(id) //Does not contain Optional()
}
You can also combine them, to do them all at one time. (Only do this if you don't want to print unless all values are non-nil)
if let id = p.product_id,
let price = p.product_price,
let description = p.productdescrption,
let productNumber = p.product_number {
//Enter code here that does something with these values
}
Note, if you aren't on swift 3, I believe you only have to write let on the first condition.
If you print any optional variable without unwrapping no matter what type it is, Optional will be appended to the variable's value.
print(p.product_price) will print Optional(220.220001)
print(p.product_descrption) will print Optional("Some description")
To print only value you need to unwrap the optional variables.
print(p.product_price!) will print 220.22
print(p.product_descrption!) will print Some description
This forced unwrapping will only work if the optionals does not contain nil. Otherwise it will give you a runtime error.
So to check for nil you can use if let statement.
No matter what type of variable. If you assign a value to an optional variable, It always enclosed with Optional(...)
Optional without forced unwrapping:
print("product_price = \(p.product_price) \n product_descrption = \(p.product_descrption)")
Output:
product_price = Optional(220.22)
product_descrption = Optional(Some description)
Optional with forced unwrapping:
print("product_price = \(p.product_price!) \n product_descrption = \(p.product_descrption!)")
Output:
product_price = 220.22
product_descrption = Some description

value of optional type 'string?' not unwrapped when checking if values are empty

I'm building a very simple login verification app inside of xCode 7 using Swift. I'm extremely new to Swift and building apps in general, so I'm having some difficulty with a part of my code.
I'm checking whether or not a user has left any fields empty, and if they have, they will receive an error alert message.
However, when I go to build my project, I get the error:
Value of optional type 'String?' not unwrapped;
This is my code:
let userEmail = userEmailTextField.text
let userPassword = userPasswordTextField.text
let userRepeatPassword = repeatPasswordTextField.text
if(userEmail.isEmpty || userPassword.isEmpty || userRepeatPassword.isEmpty){
displayAlertMessage("All fields are required.") // custom made function
return;
}
Any help is appreciated.
Also, If someone could explain why my code is not functioning correctly, that would be awesome! Because, I can't seem to understand other forums explanations or fixes.
The problem here is that the property text of UITextField is an optionl string so you have to change like this:
let userEmail = userEmailTextField.text!
let userPassword = userPasswordTextField.text!
let userRepeatPassword = repeatPasswordTextField.text!
or use it like this
guard let userEmail = userEmail, let userPassword = userPassword, let userRepeatPassword = userRepeatPassword where !userEmail.isEmpty && !userPassword.isEmpty && !userRepeatPassword.isEmpty else {
displayAlertMessage("All fields are required.") // custom made function
return;
}
As already noted, UITextFields property text is of type String? (aka Optional<String>), so you cannot directly apply methods or get properties of String.
Forced unwrapping (!) would be very risky, as that property may actually be nil.
In such cases, you have some options to treat the Optional value:
Use optional bindings, its representative is if let, but guard let or sometimes while let may be useful.
Use optional chaining, represented with ?.. Maybe you are using this somewhere else.
Giving default value using nil-coalescing operator ??.
With the latter two, I get this line:
if((userEmail?.isEmpty ?? true) || (userPassword?.isEmpty ?? true) || (userRepeatPassword?.isEmpty ?? true)) {
As you see, userEmails type is String?, so I have chosen optional chaining:
userEmail?.isEmpty
Which may return three kinds of values:
Optional.Some(true)
Optional.Some(false)
Optional.None (this is called nil)
(I omitted specifying <Bool>, for readability.)
It's still Optional, so I added ?? true to supply a default value for nil case.
userEmail?.isEmpty ?? true
lhs:Optional.Some(true) -> true (left hand side of ?? is not nil, use lhs value unwrapped)
lhs:Optional.Some(false) -> false (left hand side of ?? is not nil, use lhs value unwrapped)
lhs:Optional.None -> true (left hand side of ?? is nil, so right hand side value is used)
You know, when the text is nil, you should think it as empty, so supplying default value true for nil case is appropriate.
You need to write similar code for all three variables, and you get the line I have shown above.

Optional Type 'String??' Not Unwrapped

"Value of optional type 'String??' not unwrapped; did you mean to use '!' or '?'?" -
I got this weird compiler error today, which was entirely confusing due to the two question marks after String.
I have a dictionary s, of type [String : String?], and a function which accepts all arguments as String?s. Specifically (from 5813's method of copying user-selected information into a dictionary), I have an elaborated version of the following:
func combine(firstname: String?, lastname: String?) {...}
var text = combine(s["kABPersonFirstNameProperty"], lastname: s["kABPersonLastNameProperty"])
I'm getting the error on the second line, and I'm wondering why it's so. If the values in s are of type String?, shouldn't that be accepted by combine(), since it's arguments are supposed to be of the same type? Why, then, would I get this error and how can I fix it?
Dictionary<T1, T2>[key] returns T2?. This is to return nil in case key doesn't exist.
So if T2 is String?, s[key] returns String??
You cannot pass String?? as String?
You can call like this to unwrap and prepare for non-existing key as well
var text = combine(s["kABPersonFirstNameProperty"] ?? nil, lastname: s["kABPersonLastNameProperty"] ?? nil)
By the way, code below will not set value to nil but remove the entire entry from the dictionary
s[key] = nil
If you want the value to be nil instead of removing entry, you will have to do this
s[key] = nil as String?
It is once optional because your dictionary value is optional. And it is optional again, because dictionary[key] returns optional. So you need to unwrap it twice.
Try this in a playground to understand the problem (and see possible solution):
let oos: String?? = "Hello"
print(oos)
if let os = oos { // Make String?
print(os)
if let s = os { // Make ordinary String
print(s)
}
}
Prints:
Optional(Optional("Hello"))
Optional("Hello")
Hello
But you could use other ways than if let to unwrap, too. For example:
print(oos! ?? "n/a")
Will force unwrap it once and then print either the inner String or n/a in case of nil...
Maybe the easiest solution would be to make the dictionary hold String instead of String?. Then you don't have the unwrapping problems which are described in other solutions.
Or do you really have to store String? types?
Do you want to differentiate between 'key exists but holds nil' and 'key does not exist'?

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