going from optionals with swift map function - swift

I'm a bit new to swift optionals and am looking for a graceful way of dealing with transforming optionals to non-optionals in a map function.
I'd like my map transformation to not include nulls and also to have the most succint optionals syntax.
let result = JSON as? [Dictionary<String,String>]
//how can I avoid the result != nil check here with a more graceful optionals syntax
if (result != nil && response!.statusCode == 200 && error == nil){
let strHighlights = result!.map { json in
//is there a more 'optionals' syntax for this so that it doesn't return nulls in the map?
return json["uname"]! //i would like to avoid the bang! here as that could cause an error
}
callback(success: true ,errorMsg: nil, highlights:strHighlights)
}
else{
callback(success: false,errorMsg:error?.localizedDescription, highlights:[])
}
Can I do this more gracefully than checking to see if result != nil in the 3rd line? Also, in the map function I'd prefer not to do the hard ! cast in the json["uname"] in case it doesn't exist. Can I use optional syntax to gracefully ignore a nil value in that optional so that it doesn't get returned in the map? I can do a json["uname"] != nil check but that seems a bit verbose and makes me wonder if there is a more succint optionals syntax in swift for that.

I think this is what you want:
if let result = result, response = response
where response.statusCode == 200 && error == nil {
let strHighlights = result.reduce([String]()) { array, json in
if let name = json["uname"] {
return array + [name]
} else {
return array
}
}
callback(success: true ,errorMsg: nil, highlights:strHighlights)
} else {
callback(success: false,errorMsg:error?.localizedDescription, highlights:[])
}
(No exclamation marks required)
Oh and btw: Every kind of those functions (map, filter, reversed, ... Can be expressed in a single reduce function. Also combinations of them can often be represented with a single reduce function.

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) {
}

How to read null values from SQLite database using Swfit [duplicate]

I am reading from a dbtable and get an error at a specific position of the table. My sql is ok, because I could already read from the same table, but at a specific row I get an error and I would like to know howto handle this error. I am not looking for a solution to solve my db-issue, I am just looking for handling the error, so it doesn't crash.
I have the following code :
let unsafepointer=UnsafePointer<CChar>(sqlite3_column_text(statement, 2));
if unsafepointer != nil {
sText=String.fromCString(unsafepointer)! // <<<<<< ERROR
} else {
sText="unsafe text pointer is nil !";
}
I get an error:
"fatal error: unexpectedly found nil while unwrapping an Optional value"
at line marked with <<<<<< ERROR.
The unsafe pointer's value is not nil:
pointerValue : 2068355072
How can I handle this error, so my app is not crashing ?
Another possible solution is this:
let unsafepointer=UnsafePointer<CChar>(sqlite3_column_text(statement, 2));
var sText = "unsafe text pointer is nil !";
if unsafepointer != nil{
if let text = String.fromCString(unsafepointer) as String?{
sText = text;
}
}
let statementValue = sqlite3_column_text(statement, 2)
var sText = withUnsafeMutablePointer(&statementValue) {UnsafeMutablePointer<Void>($0)}
if sqlite3_column_text(statement, 2) != nil {
print("do something")
} else {
YourString = ""
}

Guard statement with two conditions in Swift

My understanding is that having two conditions in a guard statement separated by a comma functions imposes the requirement that they both be true. I can write a guard statement with either one independently and the code compiles but when I combine them with a comma, it gives an error. Is there anything wrong with my syntax or can anyone explain why it fails to compile?
guard (mode != "mapme") else { //compiles
}
guard (!annotation is MKUserLocation) else { //compiles
}
guard (mode != "mapme",!(annotation is MKUserLocation)) else { //gives error:'(Bool, Bool)' is not convertible to 'Bool'
}
You are using too many pointless parentheses, basically don't use parentheses in if and guard statements in simple expressions.
The error occurs because the compiler treats the enclosing parentheses as tuple ((Bool, Bool)), that's what the error message says.
guard mode != "mapme" else {
guard !(annotation is MKUserLocation) else { // here the parentheses are useful but the `!` must be outside of the expression
guard mode != "mapme", !(annotation is MKUserLocation) else {
If you want to use parenthesis, just use && operator (or || if you want an OR clause)
guard (mode != "mapme" && !(annotation is MKUserLocation)) else {
In swift you do not need the outer brackets on, if statements, for loops and all that. It is generally considered good practice not to include them, in your case here the guard statement becomes a tuple when you include the brackets. So just change your code to this and it should all work.
guard mode != "mapme" else { //compiles
}
guard !(annotation is MKUserLocation) else { //compiles
}
guard mode != "mapme", !(annotation is MKUserLocation) else {
}

How to check conditions of two parameters in my case

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).

Checking for nil parameter and if that parameter is an empty string in Swift

There may or may not be an easier way to write this, but I feel like being a novice at Swift, I am probably missing something. I have a parameter (fileName) for a method that is an optional String? I need to check if it is nil, or if it is an empty String. This is the code I have, and it works fine, but it seems like it could be a bit more concise/readable.
func writeFile(fileName: String?, withContents contents: String, errorCallback failureCallback: RCTResponseSenderBlock, callback successCallback: RCTResponseSenderBlock) -> Void {
// If fileName has a value -- is not nil
if let fileName = fileName {
// Check to see if the string isn't empty
if count(fileName) < 1 {
// Craft a failure message
let resultsDict = [
"success": false,
"errMsg": "Filename is empty"
]
// Execute the JavaScript failure callback handler
failureCallback([resultsDict])
return; // Halt execution of this function
}
// else, fileName is nil, and should return the same error message.
} else {
// Craft a failure message
let resultsDict = [
"success": false,
"errMsg": "Filename is empty"
]
// Execute the JavaScript failure callback handler
failureCallback([resultsDict])
return; // Halt execution of this function
}
}
How about
First create a nil string optional to set up the example
var fileName: String?
Now code that lets you see if filename is nil/empty in one simple line:
if (fileName ?? "").isEmpty
{
println("empty")
}
else
{
println("not empty")
}
This uses ??, the Swift "nil coalescing operator". (link)
For the expression:
a ?? b
Where a is an optional it says:
if a is not nil, return a. If a is nil, return b instead.
So
if (fileName ?? "").isEmpty
Says
First, evaluate fileName and see if it's nil. If so, replace it with an empty string.
Next, check the result to see if it's empty.
You have the right approach. All you need to do is combine your IF statements into one line:
func writeFile(fileName: String?, withContents contents: String, errorCallback failureCallback: RCTResponseSenderBlock, callback successCallback: RCTResponseSenderBlock) -> Void {
// Check if fileName is nil or empty
if (fileName == nil) || (fileName != nil && count(fileName!) < 1) {
// Craft a failure message
let resultsDict = [
"success": false,
"errMsg": "Filename is empty"
]
// Execute the JavaScript failure callback handler
failureCallback([resultsDict])
return; // Halt execution of this function
}
// Perform code here since fileName has a value and is not empty
}
This code first checks if fileName is nil. If so, it goes into the failure block. If not, it goes to the second conditional. In the second conditional, it will go into the failure block if fileName has a value and is empty. Only when fileName has a value and is NOT empty will it skip the failure block.
You could combine your if let and if statement into something like this:
if let str = fileName where !str.isEmpty {
println(str)
} else {
println("empty")
}
This approach is useful if you need to use the filename after checking whether it's nil or empty.