Say I have a closure with two optional parameters:
(data: MyData?, error: Error?) in
// I want to safely unwrap data & make sure error is nil
if let data = data, let error== nil {
}
The if condition above gives me error: Variable binding in a condition requires an initializer.
I understand I might have used wrong syntax with the let error==nil part. But, what is the correct way to do the condition check ?
For Swift 3 just drop let before error
if let data = data, error == nil {
// do stuff
}
Before Swift 3 the syntax was a little different
if let data = data where error == nil {
}
In your case it can be a good idea to use guard :
(data: MyData?, error: Error?) in
// I want to safely unwrap data & make sure error is nil
guard let data = data, error == nil else {
return
}
// code here
Another option is to use if case with pattern matching:
if case let (data?, nil) = (data, error) {
// ...
}
Here data? is the "optional pattern" and a shortcut for .some(data).
Related
I'm working with swift 5 and I get the following error for the code below "Initializer for conditional binding must have Optional type, not 'AdviceArticle'".
I saw a few similar issues dating back a few years but I cannot really translate the answers to my specific case.
static func loadAdviceArticle(articleID: String, completion: #escaping((AdviceArticle?) -> Void)) {
Firestore.firestore().collection("advice_articles").document(articleID).getDocument { (snapshot, error) in
if error != nil {
return
}
if let obj = try? snapshot?.data(as: AdviceArticle.self),
let article = obj {
completion(article)
}
}
}
Would you have a suggestion on how to fixe this code ?
Many thanks for your help.
try this:
guard let obj = try? snapshot?.data(as: AdviceArticle.self) else { return }
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
}
}
I got confused error handling in swift3. I try to do like "if XX function got error then try YY function"
Let me show you what I try:
class MyClass {
enum error: Error
{
case nilString
}
func findURL() {
do {
let opt = try HTTP.GET(url_adr!)
opt.start { response in
if let err = response.error {
print("error: \(err.localizedDescription)")
return //also notify app of failure as needed
}
do
{
/* This is func1. and got error. I want to if this function has error then go next function. */
try self.stringOperation(data: response.description)
}
catch{
print("doesn't work on func1. trying 2nd func")
self.stringOperation2(data:response.descritption)
}
}
} catch let error {
print("got an error creating the request: \(error)")
}
}
func stringOperation(data:String)throws -> Bool{
do{
/** 1 **/
if let _:String = try! data.substring(from: data.index(of: "var sources2")!){
print("its done")
}else{
throw error.nilString
}
IN 1: I got this fatal error on this line:
"fatal error: unexpectedly found nil while unwrapping an Optional value" and program crashed.
I googled error handling try to understand and apply to in my code. However not succeed yet. Can someone explain where did I wrong?
Additional info: I got String extension for .substring(from:...) , and .index(of:"str"). So these lines doesn't got you confused.
As a general rule, try avoiding using force unwrapping (!), where you have
if let _: String= try! data.substring...
Instead use
if let index = data.index(of: "var sources2"),
let _: String = try? data.substring(from: index) { ... } else { ... }
That way you remove the two force unwraps that may be causing your crash. You already have the if let protection for catching the nil value, so you can make the most of it by using the conditional unwrapping.
I've been looking up how to use the guard keyword in Swift. Recently a developer told me that the code below will print "success" if there's no error in the closure.
for attachment in attachments! {
attachment.fetchData { (data, error) in
guard let error = error else {
print(“success”)
return
}
print(error.localizedDescription)
}
I'm a bit confused by his statement. After reading the closure and guard keyword documentation from Apple, it looks to me like his code will print out "success" only when there is an error.
I feel like he's using it in reverse, but I may be wrong. Can someone break it down for me and explain if success is printed when there is or is not an error?
Thank you.
The use of guard to unwrap the error is very misleading. You should use it to unwrap your data and make sure there is no error and provide an early exit to your method in case of error.
Just change your guard statement to:
guard let data = data, error == nil else {
print(error ?? "")
return
}
I'm trying to use Alamofire and passing my parameters to a function I made.
Here's my code:
let msisdn : AnyObject = textFields[0].text!
//let msisdn = textFields[0].text!
let userId = "MyID"
let params = [
"msisidn":msisdn /*as AnyObject*/,
"denom_id":self.selectedGameDetail.Id /*as AnyObject*/,
"game_id":self.selectedGameDetail.GameId /*as AnyObject*/
]
print(params)
showEZLoading(true)
su.postEpins(userId, params: params, completion:{ (result, error) -> Void in
self.hideEZLoading()
if (error != nil){
print("DEBUG: API Response Error")
Utility.displayAlert(self, msg: "There's an errror fetching data from server.")
}
else {
print("DEBUG: API Response Success")
}
})
Everything in selectedGameDetail is a String.
And here's the postEpins function:
func postEpins(msisdn: String, params: [String: AnyObject]?, completion:(result: JSON, error: NSError?) -> Void) {
print("POST EPINS")
}
Doesn't do anything yet. But, whenever the app gets to the function call, I get this:
fatal error: unexpectedly found nil while unwrapping an Optional value
I'm positive it has something to do with the params, but I'm 100% sure. Yes, params has stuff in it. Check below.
What I've tried:
Well, if you see a comment in my code, I've pretty much tried those. And I have no idea what else to do.
For reference, that exact same code works on another part of the app, minus the userID - and I also tried removing that, but it still gave me the above error.
I found this regarding the params:
I noticed that one of the values is an NSTaggedPointerString, whereas everything else is an AnyObject. Is this an issue?