So recently I switch from Xcode 9 to Xcode 10 for my iOS app development. the first thing I noticed that when I tried to print out a variable, the value is wrapped with optional, while in Xcode 9 it never happened. for example here is the code that I test.
let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String
let build = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as! String
let parameters = ["branch_id": loginData.profile.branchId,
"version": "\(version).\(build)",
"os_name" : "ios",
"user_id" : loginData.uid]
print(parameters)
and the output was like :
["os_name": "ios",
"branch_id": Optional("2"), "version": "1.5.8.3",
"user_id": Optional("1141")]
I've tried to force unwrap the code with exclamation mark
"branch_id": loginData.profile.branchId!
,
or even better with coalescing operator
"branch_id": loginData.profile.branchId ?? "0"
It works, but I have like, 30+ lines of code with the same problem, do I need to do it one by one? Or is there a way to change this behaviour?
FYI I'm using Swift 4 for my project.
Edit : FYI this was tested on iOS 12, while before in Xcode 9 was tested in iOS 11
Edit:
To answer matt comment asking info about where loginData.profile.branchId
come from, here it is.
So, the data is fetched from data model, and I use this code to fetch it:
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "User")
let fetchResults = try context.fetch(request) as? [NSManagedObject]
let loginData = fetchResults![0]
let profile = loginData.value(forKey: "profile") as! NSManagedObject
self.profile = Profile()
self.profile.branchId = profile.value(forKey: "branchId") as? String
Use Optional Unwrapping with if-let statement
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "User")
if let fetchResults = try context.fetch(request) as? [NSManagedObject]{
let loginData = fetchResults[0]
let profile = loginData.value(forKey: "profile") as! NSManagedObject
self.profile = Profile()
if let branchId = profile.value(forKey: "branchId") as? String{
self.profile.branchId = branchId
}
}
if let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String, let build = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as? String{
let branchId = loginData.profile.branchId ?? ""
let branchId = loginData.uid ?? ""
let parameters = ["branch_id": branchId,
"version": "\(version).\(build)",
"os_name" : "ios",
"user_id" : login_tty.uid]
print(parameters)
}
Never use force unwrapping, i mean ! directly, it may result in crash,
instead safely unwrap using if let
and guard let
if you are printing an optional value Xcode prints the value warapped with the word optional("value").
if you want to avoid this you must upwarapped the value.
you have 3 ways to do that:
the careful way, use guard let or if let:
if let branchId = profile.value(forKey: "branchId") as? String {
//here branchId != nil
}
guard let branchId = profile.value(forKey: "branchId") as? String else { return }
the force unwarapped way:
let branchId = profile.value(forKey: "branchId") as! String
on that way, if the value is nil the app will crash so be careful
use default value:
let branchId = profile.value(forKey: "branchId") as? String ?? "default value"
I ended up using coalescing operator which is ?? ""
and implemented it my code like:
var parameters = [String: Any]()
if loginData.profile != nil {
if loginData.profile.branchId != "" {
let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String
let build = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as! String
parameters = ["branch_id": loginData.profile.branchId ?? "",
"version" : "\(version).\(build)",
"os_name" : "ios",
"user_id" : loginData.uid ?? ""
]
}
}