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

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

Related

I am trying to validate an email field using Regex in Swift

I am simply trying to validate an email using an expression. I have created a Struct that I use for my form fields.
let emailRegEx = "[A-ZO-9a-z._%+-]+#[A-Za-zO-9.-J+|l.[A-Za-z]{2,64}"
var isEmailValid: Bool {
!email.isEmpty &&
if email.ranges(of: emailRegEx, options: .regularExpression) == nil {
return self
}
}
It keeps throwing this error...Cannot infer contextual base in reference to member 'regularExpression', and Expected expression after operator, lastly Extra argument 'options' in call.
Your if is in the wrong place, and .ranges should be .range.
Assuming your emailRegEx is correct, try this:
var isEmailValid: Bool = !email.isEmpty && (email.range(of: emailRegEx, options: .regularExpression) != nil)
Using a computed var, use this:
var isEmailValid: Bool {
!email.isEmpty && (email.range(of: emailRegEx, options: .regularExpression) != nil)
}
You could also try this regex for email:
let emailRegEx = #"^\S+#\S+\.\S+$"#
Or
let emailRegEx = #"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+#[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$"#
See also this SO post: How to validate an e-mail address in swift?

How to unwrap optional value in 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.

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

going from optionals with swift map function

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.

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.