The following code throws a message which says "Initializer for conditional binding must have Optional type, not 'AnyObject'"
func parseData2(){
var data:NSData?
if let data2 = data {
do {
let details = try NSJSONSerialization.JSONObjectWithData(data2, options: .AllowFragments)
if let actualDetails = details where actualDetails.isKindOfClass(NSDictionary) {
print("Parse Data")
}
}catch {
print("Error \(error)")
}
}
}
To resolve the above error I used the following code.
func parseData2(){
var data:NSData?
if let data2 = data {
do {
let details:AnyObject = try NSJSONSerialization.JSONObjectWithData(data2, options: .AllowFragments)
if let actualDetails:AnyObject = details where actualDetails.isKindOfClass(NSDictionary) {
print("Parse Data")
}
}catch {
print("Error \(error)")
}
}
}
Is there any better approach then the above or my code might crash?
There is one more code which I want to add considering nil check,type check and then type cast check. The reason behind that Swift offers great flexibility but litle bit difficult to fix issues. Let's say I have a dictionary, cityDetails and I am trying to get data for self.cityZipCode and self.cityIdentifier, which are optional, defined as var cityZipCode:Int? and var cityIdentifier:Int?
if let cityBasic = cityDetails["basicDetails"] where
cityBasic!.isKindOfClass(NSDictionary) {
self.cityZipCode = (cityBasic as! NSDictionary)["zip"].integerValue ?? 0
self.cityIdentifier = (cityBasic as! NSDictionary)["cityId"].integerValue ?? 0
}
No need to unwrap the result from try
. It is not an optional. You do need to cast the result from try
to an NSDictionary
. Use as?
to downcast it.
Best practice: full access to returned error for good error handling
func parseData2(){
var data:NSData?
if let data2 = data {
do {
let details = try NSJSONSerialization.JSONObjectWithData(data2, options: .AllowFragments)
if let detailsDict = details as? NSDictionary {
print("Parse Data")
} else if let detailsArray = details as? NSArray {
print("array")
}
} catch {
print("Error \(error)")
}
}
}
Quick and dirty: error handling is not for me!
func parseData2(){
var data:NSData?
if let data2 = data {
let details = try? NSJSONSerialization.JSONObjectWithData(data2, options: .AllowFragments)
if let detailsDict = details as? NSDictionary {
print("Parse Data")
} else {
print("details might be nil, or not an NSDictionary")
}
}
}
Bad Ass Mode: crashes are features
func parseData2(){
var data:NSData?
if let data2 = data {
let details = try! NSJSONSerialization.JSONObjectWithData(data2, options: .AllowFragments) as! NSDictionary
}
}
Some extra info on multiple unwraps : Drop the code below in a playground.
struct SomeStruct {
var anOptional : Int?
init() {
}
}
func unwrapWithIfLet() {
if let unWrappedStruct = myStruct, let unWrappedSomething = unWrappedStruct.anOptional {
print("multiple optional bindings succeeded")
// both unWrappedStruct and unWrappedSomething are available here
} else {
print("something is nil")
}
}
func unwrapWithGuard() {
guard let unWrappedStruct = myStruct, let unWrappedSomething = unWrappedStruct.anOptional else {
print("something is nil")
return
}
print("multiple optional bindings succeeded")
// both unWrappedStruct and unWrappedSomething are available here
}
var myStruct : SomeStruct?
//unwrapWithGuard()
//unwrapWithIfLet()
myStruct = SomeStruct()
myStruct!.anOptional = 1
unwrapWithGuard()
unwrapWithIfLet()