Remove Force Unwrapping - swift

Remove force unwrapping
private func getLanguageCode() -> String {
return Locale.current.languageCode!
}
After removing force unwrapping
private func getLanguageCode() -> String? {
if let language = Locale.current.languageCode {
return language
}
return nil
}
Correct??
for this
lazy var commonErrorList : Dictionary<String, AnyObject>? = {
let path = Bundle.main.path(forResource: "CommonErrorCodes", ofType: "plist")
return NSDictionary(contentsOfFile: path!) as? [String : AnyObject]
}()
what it should be after removing forced unwrapping?

You could just
return Locale.current.languageCode
without the forced unwrap, if you just return nil anyway.

You may try guard to prevent nested if statement in the future. In guard statement it would be something like this:
private func getLanguageCode() throws -> String {
guard let language = Locale.current.languageCode else {
throw LanguageError.CanNotGetCode
}
return language
}
or without throws
private func getLanguageCode()-> String? {
guard let language = Locale.current.languageCode else {
return nil
}
return language
}
You may use throwing function if in the future you want to handle your function error.

Your code looks fine to me. You can consider also using guard statement.
private func getLanguageCode() -> String? {
guard let language = Locale.current.languageCode else { return nil }
return language
}

If you want to return a non-optional String, you can just do:
private func getLanguageCode() -> String {
return Locale.current.languageCode ?? ""
}
If you prefer to return a String?, then:
private func getLanguageCode() -> String? {
return Locale.current.languageCode
}
If you still want to detect the nil condition inside your function for whatever reason:
private func getLanguageCode() -> String? {
guard let language = Locale.current.languageCode else {
// Do something here...
return nil
}
return language
}

If you don't want to deal with an unwrap, you can easily do this:
private func getLanguageCode() -> String {
return Locale.current.languageCode ?? "en"
}
This will return the value of the optional if available, otherwise it will return the specified value.
You can also use a property to get the expected value:
private var getLanguageCode: String {
return Locale.current.languageCode ?? "en"
}
The final result is pretty the same, but you get rid of the '( )' notation :-)

Related

How do I return safely unwrapped optionals which are outside of their scope?

I'm a noob, bear with me:
func createEmployeeCode() -> String? {
let email = UserDefaults.standard.object(forKey: "email_Saved") as? String
let employeeCode = UserDefaults.standard.object(forKey: "employeeCode_Saved") as? String
if let emailString = email,
let employeeCodeString = employeeCode {
return (emailString+employeeCodeString)
}
return (emailString+employeeCodeString) //ERROR: Use of unresolved identifier 'employeeCodeString' & Use of unresolved identifier 'emailString'
}
I understand the reason the error shows is because I'm trying to return something that is in a different scope here, but how else can I get the function to return the 2 strings together without the "Optional[...]" tag?
Here's how I'd expect it to be done in a normal production app
(You wouldn't do any of this in a normal production app! But this is the "idiom" you're looking for.)
func createCodeIfPossible() -> String? {
guard let e = UserDefaults.standard.object(forKey: "email_Saved") else {
print("serious problem, there's no email saved")
// at this point the app is completely buggered, so give up
return ""
}
guard let c = UserDefaults.standard.object(forKey: "employeeCode_Saved") else {
print("serious problem, there's no code saved")
// at this point the app is completely buggered, so give up
return ""
}
return e + c
}
Do note that the return is largely meaningless - in the app in question, if one of the guards breaks you are "totally screwed". I'd probably just return a blank string (or more likely something like "name_error") since at this point the app architecture is hopelessly broken.
(Sidenote: use UserDefaults.standard.string(forKey:).)
The issue is that you can't know if those strings DO both exist or not--if they do, you already have a great if let that returns your answer. The question now is what do you want to do if one or both are nil? Maybe you'd like to return nil from the entire function. If so,
func createEmployeeCode() -> String? {
let email = UserDefaults.standard.string(forKey: "email_Saved")
let employeeCode = UserDefaults.standard.string(forKey: "employeeCode_Saved")
if let emailString = email,
let employeeCodeString = employeeCode {
return (emailString+employeeCodeString) //successful unwrapping, let's concatenate!
}
return nil //if one or both `if let`s fail, we end up here
}
Of course, you could do whatever you'd like in that "bad" case. Maybe you'd like to show whatever string you DO have. In that case:
func createEmployeeCode() -> String {
let email = UserDefaults.standard.string(forKey: "email_Saved")
let employeeCode = UserDefaults.standard.string(forKey: "employeeCode_Saved")
return (email ?? "") + (employeeCode ?? "") //this works in the "good" case, too, and uses the nil coalescing operator `??`
}
In this case, you can see that the return value is no longer optional. This is because even if neither string exists, it'll concatenate two empty strings. If this feels icky, you could keep your optional return value and do a quick check before returning:
if email == nil && employeeCode == nil { return nil }
func createEmployeeCode() -> String {
var finalString = String()
if let email = UserDefaults.standard.string(forKey: "email_Saved"), let employeeCode = UserDefaults.standard.string(forKey: "employeeCode_Saved") {
finalString = email + employeeCode
}
return finalString
}
When assign back the values from userDefaults you've been trying to get as an object instead of string
func createEmployeeCode() -> String? {
let email:String = UserDefaults.standard.string(forKey: "email_Saved") ?? ""
let employeeCode:String = UserDefaults.standard.string(forKey: "employeeCode_Saved") ?? ""
let emailString = "\(email)\(employeeCode)"
return emialString
}
There are different ways to solve this depending on what you're trying to achieve.
If you always want to create an employeeCode (even if the code will be empty):
Try using a "nil coalescing operator".
func createEmployeeCode() -> String {
let email = UserDefaults.standard.object(forKey: "email_Saved") as? String ?? ""
let employeeCode = UserDefaults.standard.object(forKey: "employeeCode_Saved") as? String ?? ""
return (email+employeeCode)
}
To explain what's happening here:
We're unwrapping email, if we don't find email then we default the value to an empty string, "".
We do the same with employeeCode.
This isn't a way I would solve every unwrap issue though, but it suits your usecase of email and employeeCode because you're always wanting to return something based on your original question. I've also changed the return type to non-optional.
If an employee code must always contain an email and and a code then we want to return nil if one of those isn't found.
Try using the guard statement. The guard statement is perfect for validation and very readable:
func createEmployeeCode() -> String? {
guard let email = UserDefaults.standard.object(forKey: "email_Saved") as? String else { return nil }
guard let employeeCode = UserDefaults.standard.object(forKey: "employeeCode_Saved") as? String else { return nil }
return (email+employeeCode)
}
Try this function:
func createEmployeeCode() -> String {
let email = UserDefaults.standard.object(forKey: "email_Saved") as? String
let employeeCode = UserDefaults.standard.object(forKey: "employeeCode_Saved") as? String
return [email, employeeCode].compactMap { $0 }.joined(separator: "")
}
It will return email or employeeCode or email+employeeCode in case one of them is nil or both are present, or empty String in case if both are missed out!

Accessing the optional value of a PartialKeyPath in Swift 4

Using the PartialKeyPath API, how can you access a value of a key path's reference? For example, this works for non-optional values, but not with Optional values.
The issue I'm having is that self[keyPath: keyPath] returns a non-optional Any value.
struct Element {
let name: String
let mass: Double?
func stringValue(_ keyPath: PartialKeyPath<Element>) -> String {
let value = self[keyPath: keyPath]
switch value {
case let string as String:
return string.capitalized
case nil:
return "N/A"
case let value:
return String(describing: value)
}
}
}
let element = Element(name: "Helium", mass: 4.002602)
let string = element.stringValue(\Element.mass) /* Optional(4.002602) */
The result is that case nil is never executed and the last case is being printed as Optional(value).
How can I unwrap value properly to extract the optional?
The solution was to use Mirror to unwrap the optional which seems less than optimal. Looking forward to better Reflection support in Swift!
func unwrap(_ value: Any) -> Any? {
let mirror = Mirror(reflecting: value)
if mirror.displayStyle != .optional {
return value
}
if let child = mirror.children.first {
return child.value
} else {
return nil
}
}
struct Element {
let name: String
let mass: Double?
func stringValue(_ keyPath: PartialKeyPath<AtomicElement>) -> String {
guard let value = unwrap(self[keyPath: keyPath]) else {
return "N/A"
}
switch value {
case let string as String:
return string.capitalized
default:
return String(describing: value)
}
}
}
let element = Element(name: "Helium", mass: 4.002602)
let string = element.stringValue(\Element.mass) /* 4.002602 */

how to convert null string to null swift

I am new to Swift. I tried with this Swift link Detect a Null value in NSDictionaryNSDictionary, but I failed to do so.
Data:
"end_time" = "<null>"
Here is my code:
if endTime["end_time"] is NSNull {
print("your session still available ")
}
else{
print("your session end \(endTime["end_time"])")
}
Every time it is going to else statement. May be I need to convert string to null or alternative solution. Could you help me please?
Thank you.
Here's how you check null in swift:
let time = endTime["end_time"]
if time != "<null>" {
print("time is not <null>")
}
else
{
print("time is <null>")
}
You can create a NilCheck controller to check nil or null for various datatypes. For example i have created a function to remove null [if any] from the dictionary and store the array of dictionary in Userdefaults. Please be free to ask your queries :)
func removeNilAndSaveToLocalStore(array : [[String:Any]]) {
var arrayToSave = [[String:Any]]()
for place in array {
var dict = [String:Any]()
dict["AreaId"] = NilCheck.sharedInstance.checkIntForNil(nbr: place["AreaId"]! as? Int)
dict["AreaNameAr"] = NilCheck.sharedInstance.checkStringForNil(str: place["AreaNameAr"]! as? String)
dict["AreaName"] = NilCheck.sharedInstance.checkStringForNil(str: place["AreaName"]! as? String)
dict["GovernorateId"] = NilCheck.sharedInstance.checkIntForNil(nbr: place["GovernorateId"]! as? Int)
arrayToSave.append(dict)
}
LocalStore.setAreaList(token: arrayToSave)
}
class NilCheck {
static let sharedInstance : NilCheck = {
let instance = NilCheck()
return instance
}()
func checkStringForNil(str : String?) -> String {
guard let str = str else {
return String() // return default string
}
return str
}
func checkIntForNil(nbr : Int?) -> Int {
guard let num = nbr else {
return 0 // return default Int
}
return num
} }

How to create a dictionary having string and function as key value pair in swift

I am looking to create a dictionary that will have
let urlDict:[String:Func] = ["LOGIN":getLoginURL(), "RESET":getResetPasswordURL()]
func getLoginURL() -> String{
if (sandbox == true){
return sb_login_url
}else{
return live_login_url
}
}
func getResetPasswordURL() -> String{
if (sandbox == true){
return sb_reset_url
}else{
return live_reset_url
}
}
The purpose of this dict is to get/map functions based on the KEY and as per KEY corresponding function must be called which in turn will return return urls.
I have tried naming the dictionary but I am unable to do it
let urlDict:[String:Func] = ["LOGIN":getLoginURL(), "RESET":getResetPasswordURL()]
let urlDict:[String:Function] = ["LOGIN":getLoginURL(), "RESET":getResetPasswordURL()]
let urlDict:[String:Functions] = ["LOGIN":getLoginURL(), "RESET":getResetPasswordURL()]
EDIT 1
class Constants{
private let sb_login_url = "http://IP_ADDRESS_COM/login_with_credentials"
private let live_login_url = "http://google.com"
private let sb_reset_url = "http://IP_ADDRESS_COM/forgot_password"
private let live_reset_url = "http://google.com"
func getLoginURL() -> String{
if (sandbox == true){
return sb_login_url
}else{
return live_login_url
}
}
func getResetPasswordURL() -> String{
if (sandbox == true){
return sb_reset_url
}else{
return live_reset_url
}
}
` let urlDict: [String: () -> String] = ["LOGIN": Constants.getLog‌​inURL(), "RESET":Constants.getResetPasswordURL()]
if let getFunc = urlDict[url_key] {
let url = (getFunc()) // foo}
}
You must specify the type of the functions (which are common for both getLoginURL and getResetPasswordURL) for the value slot in the dictionary, namely () -> String, a zero-arguments function returning a String instance.
func getLoginURL() -> String {
return "foo"
}
func getResetPasswordURL() -> String {
return "bar"
}
let urlDict: [String: () -> String] =
["LOGIN": getLoginURL, "RESET":getResetPasswordURL]
/* ^^^^^^^^^^^- note that you do not _call_ the functions,
as this would result in a String instance */
// get a function reference from the dictionary and invoke it
if let getFunc = urlDict["LOGIN"] {
print(getFunc()) // foo
}
After your comments below, as well as your edit, it seems you want the get... functions to be class members if your class Constants (i.e., marked static).
class Constants {
static var sandbox = true
// I've just added this to test your example
private static let sb_login_url = "http://IP_ADDRESS_COM/login_with_credentials"
private static let live_login_url = "http://google.com"
private static let sb_reset_url = "http://IP_ADDRESS_COM/forgot_password"
private static let live_reset_url = "http://google.com"
static func getLoginURL() -> String {
if (Constants.sandbox == true){
return Constants.sb_login_url
}
else {
return Constants.live_login_url
}
}
static func getResetPasswordURL() -> String{
if (Constants.sandbox == true){
return Constants.sb_reset_url
}
else {
return Constants.live_reset_url
}
}
}
let urlDict: [String: () -> String] =
["LOGIN": Constants.getLoginURL, "RESET": Constants.getResetPasswordURL]
// get a function reference from the dictionary and invoke it
if let getFunc = urlDict["LOGIN"] {
print(getFunc()) // http://IP_ADDRESS_COM/forgot_password
Constants.sandbox = false
print(getFunc()) // http://google.com
}
You could simply create a global typealias to Function prototype and can use it anywhere in your project and you don't need to use () -> String everytime when you create Dictionary.
public typealias VoidToStringFunctio‌n = () -> String
func getLoginURL() -> String {
return "url"
}
func getResetPasswordURL() -> String {
return "password"
}
and use it like this
let urlDict : [String: VoidToStringFunctio‌n] = ["LOGIN": getLoginURL, "Password": getResetPasswordURL]

cannot return String in function

I am having trouble casting an option AnyObject into a string. Whenever I try to call the fuction my program crashes with (lldb). This is the function.
func name() -> String {
print(attributes["name"])
print(attributes["name"]! as! String)
let name = attributes["name"]! as! String
return name
}
The output from the prints is:
Optional(Optional(Josh))
Josh
(lldb)
Thanks in advance for your help!
Lets say attributes is defined as follow
var attributes: NSMutableDictionary? = NSMutableDictionary()
and can be populated like follow
attributes?.setValue("Walter White", forKey: "name")
Optionals
You should design the name() function to return a String or nil (aka String? which is an Optional type)
func name() -> String? {
guard let
attributes = attributes,
name = attributes["name"] as? String else { return nil }
return name
}
The same logic can also be written this way
func name() -> String? {
return attributes?["name"] as? String
}
Now if a valid String value is found inside attributes with key name then it is returned. Otherwise the function does return nil.
Invoking the function
When using the function you should unwrap the result like this
if let name = name() {
print(name) // prints "Walter White"
}
In all these examples, attributes is defined as:
var attributes: AnyObject? = ["name": "Josh"]
Looks like the crash occurs due to type-safety issues. Try:
func name() -> String? {
if let name = attributes!["name"] as? String {
return name
}
return nil
}
Another option, which is slightly swiftier:
func name() -> String? {
guard let name = attributes!["name"] as? String else { return nil }
return name
}
Yet another option that would be using a block for the function, so that it doesn't return anything if attributes doesn't contain a key "name":
func name(block: ((text: String?) -> Void)) {
guard let name = attributes!["name"] as? String else { return }
return block(text: name)
}
// Usage:
name { text in
print(text!)
}
Prints:
Josh
if let _string = attributes["name"] as? String {
return _string
}
// fallback to something else, or make the method signature String?
return ""
When working with optionals, you don't want to just wrap things with exclamation points. If the value ever ended up not being a string, or not being there at all in the map, you're code would fail hard and potentially crash your application.
If you need a non-optional String, consider returning an empty string as a fallback method and using the if let pattern to return the optional string if it is available.
-- EDIT --
Not sure about the downvote... Here it is in a playground.
var attributes = [String:AnyObject]()
attributes["name"] = "test"
func name() -> String {
print(attributes["name"])
print(attributes["name"]! as! String)
let name = attributes["name"]! as! String
return name
}
// does not compile
//print(name())
func name2() -> String {
if let _string = attributes["name"] as? String {
return _string
}
// fallback to something else, or make the method signature String?
return ""
}
// prints test
print(name2())