How to unwrap optional value in swift? - swift

code correct
print(error!.localizedDescription)
}else{
return

To replace a nil value we need to unwrap optional value this done according to type of value.
i.e. if value is string then we need to add ?? "" or if value is double we need to add ?? 0.0
As in case of the above scenario (EmailTextField.text ?? "") this is the format to replace unwrap optional value .
Auth.auth().createUser(withEmail: (txtEmail.text ?? ""), password: (txtPass.text ?? "")) { (result, error) in
if let _eror = error {
//something bad happning
print(_eror.localizedDescription )
}else{
//user registered successfully
print(result)
}
}

This error clearly indicates that you have forced unwrap the optional somewhere in your code.
Remove force unwrapping (!) by optional binding in your code.
Ways to optional binding...
if let
guard let
nil coalescing i.e ??
Look for exclaimation mark in your code, where you have force
unwrapped and replace it with one of the above way.

Related

How to use OR for a value that can be nil?

This is very basic but I'm kinda confused why my code isn't working. I have a user that has an optional username and I am trying to check whether the email or username contains my search query
struct ChatUser: Codable, Identifiable {
let email: String
var username: String?
}
#State var user: ChatUser
if user.email.lowercased().contains(search.lowercased()) ||
user.username.lowercased().contains(search.lowercased()) {...}
It works if I unwrap user.username! but then my App crashes due to unwrapping nil values. How do I check for user.username != nil and then force unwrap in the if check?
Calling lowercased() again and again is unnecessarily expensive.
But with your given syntax this is the swifty way
if user.email.lowercased().contains(search.lowercased()) ||
user.username?.lowercased().contains(search.lowercased()) == true {...}
The Optional Chaining expression returns nil immediately if username is nil.
However range(of:options: can handle the optional and the case
if user.email.range(of: search, options: .caseInsensitive) != nil ||
user.username?.range(of: search, options: .caseInsensitive) != nil {
}
You can use nil-coalescing(??) to unwrap your optional value.
if user.email.lowercased().contains(search.lowercased()) ||
user.username?.lowercased().contains(search.lowercased()) ?? false {
}
if user.email.lowercased().contains(search.lowercased()) ||
(user.username.map { $0.lowercased().contains(search.lowercased()) } ?? false) {
}

please give me some solution to this error Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value [duplicate]

This question already has answers here:
What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean?
(16 answers)
Closed 3 years ago.
func doGetLocalDataUser() -> logInResponse {
var localData : logInResponse? = nil
if let userData = UserDefaults.standard
.data(forKey: ConstantStrings.KEY_USER_LOGIN_DATA),let user = try? JSONDecoder()
.decode(logInResponse.self ,from: userData){
localData = user
}
return localData!
}
I would change the method to this:
func doGetLocalDataUser() -> logInResponse? {
guard let userData = UserDefaults.standard.data(forKey: ConstantStrings.KEY_USER_LOGIN_DATA), let user = try? JSONDecoder().decode(logInResponse.self ,from: userData) else {
return nil
}
return user
}
Keep in mind JSON decoding can fail (maybe has wrong format), therefore user will be nil, and this method can return nil
localData is nil, so you are force unwrapping localData (as a logInResponse) illegally.
If your optional chaining finds nil at any point (for example your userData doesn't exist in UserDefaults / has the wrong type) then it won't execute.
You are declaring this doGetLocalDataUser() function to return a non optional logInResponse type and force unwrapping a nil value to try and retrieve one. Best practice is to avoid the force unwrap "bang" operator "!" because it can lead to fatal errors like this.
Simple solution is to change your method to return an optional logInResponse? type, and eliminate the bang operator:
func doGetLocalDataUser() -> logInResponse? {
if let userData = UserDefaults.standard.data(forKey: ConstantStrings.KEY_USER_LOGIN_DATA), let user = try? JSONDecoder().decode(logInResponse.self ,from: userData){
return user
} else {
return nil
}
}

How can I use try with the coalescing operator?

I'm trying to assign a value to x from a function f that takes one parameter (a string) and throws.
The current scope throws so I believe a do...catch isn't required.
I'm trying to use try with the coalescing operator ?? but I'm getting this error: 'try' cannot appear to the right of a non-assignment operator.
guard let x = try f("a") ??
try f("b") ??
try f("c") else {
print("Couldn't get a valid value for x")
return
}
If I change try to try?:
guard let x = try? f("a") ??
try? f("b") ??
try? f("c") else {
print("Couldn't get a valid value for x")
return
}
I get the warning Left side of nil coalescing operator '??' has non-optional type 'String??', so the right side is never used and the error: 'try?' cannot appear to the right of a non-assignment operator.
If I put each try? in brackets:
guard let x = (try? f("a")) ??
(try? f("b")) ??
(try? f("c")) else {
print("Couldn't get a valid value for x")
return
}
It compiles but x is an optional and I would like it to be unwrapped.
if I remove the questions marks:
guard let x = (try f("a")) ??
(try f("b")) ??
(try f("c")) else {
print("Couldn't get a valid value for x")
return
}
I get the error Operator can throw but expression is not marked with 'try'.
I'm using Swift 4.2 (latest in Xcode at time of writing).
What is the correct way to do this to get an unwrapped value in x?
Update:* f()'s return type is String?. I think the fact that it's an optional string is important.
A single try can cover the entire expression, so you can just say:
guard let x = try f("a") ?? f("b") ?? f("c") else {
print("Couldn't get a valid value for x")
return
}
Same goes for try?:
guard let x = try? f("a") ?? f("b") ?? f("c") else {
print("Couldn't get a valid value for x")
return
}
Although note that in Swift 4.2 x will be String? due to the fact that you're applying try? to an already optional value, giving you a doubly-wrapped optional which guard let will only unwrap one layer of.
To remedy this, you could coalesce to nil:
guard let x = (try? f("a") ?? f("b") ?? f("c")) ?? nil else {
print("Couldn't get a valid value for x")
return
}
But in Swift 5 this is unnecessary due to SE-0230, where try? f("a") ?? f("b") ?? f("c") will be flattened into a single optional value automatically by the compiler.

Swift 3 better way to unwrap an optional

Right now I have some code that looks like the following:
let msg: String? = myStr.removingPercentEncoding ?? nil
print("msg \(msg!)")
I really don't like the use of ! in msg! as that can possibly throw an exception, I believe.
What's the best way to call myStr.removingPercentEncoding if myStr is not nil and then unwrap msg without throwing an exception?
The proper way would be:
if let msg = myStr.removingPercentEncoding {
print("msg \(msg)")
}
Here, msg is only valid inside the if statement and only if myStr.removingPercentEncoding isn't nil.
If you wish to print something if myStr.removingPercentEncoding is nil, then you could and an else:
if let msg = myStr.removingPercentEncoding {
print("msg \(msg)")
} else {
print("msg has no value")
}
Read up on Optional Binding in the The Swift Programming Language book.
This line is completely useless, when myStr.removingPercentEncoding is nil, then nil (right hand side of ??) is assigned to msg:
let msg: String? = myStr.removingPercentEncoding ?? nil
Why don't you make it as:
let msg: String = myStr.removingPercentEncoding ?? ""
print("msg \(msg)")

Swift: Optional Text In Optional Value

How to remove Optional("") text on optional value when displaying without forcing to !.
Update
// I have somthing like this declared outside class
// I put question mark wrapper since I don't know when this session might have a value
var url = "\(self.session?.apiURL)/api/products.json"
// private session
private var _session:Session?
class MyClass
{
.
.
.
// the value of apiURL depends on session, session has optional value and declared as
// custom lazy loaded var session
var session:Session?
{
get
{
if _session == nil
{
_session = // fetch from coredata store if there is an active session. Might return nil
// if no active session
if _session == nil
{
// I just print "No active session"
}
}
// return _session may or may not contain any value
return _session
}
}
}
When the session has a value the url has a value:
Optional("my_api_url_here")/api/products.json
You can use this pod http://cocoapods.org/pods/NoOptionalInterpolation.
Alternatively, add this code to your project to remove the Optional(...) and nil text in string interpolation:
public protocol Unwrappable {
func unwrap() -> Any?
}
extension Optional: Unwrappable {
public func unwrap() -> Any? {
switch self {
case .None:
return nil
case .Some(let unwrappable as Unwrappable):
return unwrappable.unwrap()
case .Some (let some):
return some
}
}
}
public extension String {
init(stringInterpolationSegment expr: Unwrappable) {
self = String(expr.unwrap() ?? "")
}
}
Please note that simply overriding the description function of Optional won't work for string interpolation, although it works for print.
you can use ?? (null coalescing operator) to unwrap it and provide a default value if it is nil
let sessionApiURL = self.session?.apiURL ?? ""
var url = "\(sessionApiURL)/api/products.json"
If you want to without optional value you have to unwrap the Optional. You can use "optional binding" to unwrap an Optional:
if let url = self.session?.apiURL{
//you can use url without optional
print(url)
}
You can check my example in online swift playground for better understand.