Swift remove optional from Dictionary of Dictionary - json

I'm taking data from an api in the form of JSON. I get a variable of dynamicType Swift.Dictionary<NSObject, Swift.AnyObject> and call this variable myDictionary. When I ask for print(myDictionary["keyA"]) it returns the value (inner dictionary) associated with "keyA", but it returns it as a Swift.Optional<Swift.AnyObject>.
How do I set a variable with the inner dictionary that isn't optional? Or how to I access the inner dictionary values?

All dictionary accesses are returned as optionals because the key used might not exist in the dictionary, and thus nil is returned in that case. You can use optional casting as? along with optional binding if let to make sure the value exists, that it is a dictionary as expected, and unwrap it:
if let innerDictionary = myDictionary["keyA"] as? [NSObject: AnyObject] {
// if we get here, "keyA" is a valid key in myDictionary and
// we got the type right. innerDictionary is now unwrapped and ready
// to use.
}
I used [NSObject: AnyObject] as the innerDictionary type. If you know more about it, you can use a more specific cast, for example as? [String: String] if you know that both keys and values are of type String. If you are wrong, the optional cast will return nil and the block will not be entered because the optional binding will not succeed.

Related

having trouble drilling down into response json using alamofire. Swift

Ok so im having trouble drilling down into the response json that is retrieved in the below code.
Snapshot 1:
Snapshot 2:
I get the json above as a response, yet when I try to drill down into the json I cannot access the key "Address" or any other key that is held under bookings. it finds bookings but then assigns the variables i created for each key's value (address, state, zipcode, and city) and assigns these variables as null. My only theory is that the response json has "()" right after bookings instead of the normal "{}". Those brakets do appear after the parentheses, so how would i drill into that with out a key? I am still new to the app dev world so i could be completely wrong, just this request method has worked for me in the past when i've received "{}" after the first key.
1) You are using method valueForKeyPath() to get value from dictionary.
Change it to valueForKey().
2) Value for key "bookings" will give you array.
Try this code.
let data = JSON as! NSDictionary;
//value for key "bookings" will give you array
if let bookings = data.valueForKey("bookings") as? NSArray {
let bookingObj = bookings[0] as! NSDictionary;
self.address = bookingObj.valueForKey("address");
self.state = bookingObj.valueForKey("state");
self.zip = bookingObj.valueForKey("zip");
self.city = bookingObj.valueForKey("city");
}
FYI Please Note that, method valueForKeyPath() returns array of value for particular key from the array of dictionaries.
e.g. suppose you have multiple objects of bookings array, and you use
let arrayAddresses = bookings.valueForKeyPath("address") as! NSArray
this will return string array containing only address of all object.
Another point, '()' means Array Value, '{}' means Dictionary value.
I'd suggest using Swift types (like [String: AnyObject]) instead of Foundation types (like NSDictionary), and on top of that, you should print out when something fails so you know what's wrong. So starting from your let data = ... line, try this instead:
if let data = JSON as? [String: AnyObject],
bookings = data["bookings"] as? [[String: AnyObject]],
booking = bookings[0] {
self.address = booking["address"] as? String
self.state = booking["state"] as? String
self.zipCode = booking["zip"] as? String
self.city = booking["city"] as? String
print(self.address)
} else {
print("Couldn't parse booking from JSON")
}
More on why typing is important (and why you should use [[String: AnyObject]] instead of NSArray) in this article. You can be more specific and more concise if you use proper types.

Cannot convert value of type 'AnyObject?' to expected argument type '[AnyObject]!

I'm using the swift lib "Sync" from Hyperoslo to convert a JSON user to a Core Data object.
let user = JSON.valueForKey("user")
Sync.changes(user , inEntityNamed: "User", dataStack: DataManager.manager, completion: { (response ) -> Void in
print("USER \(response)")
})
but when a set the first parameter of this method with my JSON object, I have the pre-compiler error:
Cannot convert value of type 'AnyObject?' to expected argument type
'[AnyObject]!'
If a replace my first line by...
let user = JSON.valueForKey("user") as! [AnyObject]
...the app crash with this error:
Could not cast value of type '__NSCFDictionary' (0x3884d7c8) to
'NSArray' (0x3884d548).
How to deal with this?
SOLVED thanks to the explanations from #Eric.D
let user = [JSON.valueForKey("user")!]
The first parameter for changes() should be an implicitly unwrapped array of AnyObject as specified here:
https://github.com/hyperoslo/Sync#swift
but your object user is an optional AnyObject.
Solution: safely unwrap user then put it inside a [AnyObject] array before using it in changes().
To start, user is an optional AnyObject. You can never expect that you can use an optional where anything non optional is required. Typically you will use "if let" to check whether the optional is there.
But really, do you want to put an AnyObject in your database? This is asking for trouble. Check first that it has the right type.

How do you create a SwiftyJSON dictionary out of optional AnyObjects?

I recently ran into a very time-consuming issue for a simple task of creating a JSON dictionary with optional objects. I'm using SwiftyJSON.
If I create the following dictionary, I get thrown errors
JSON type doesn't have an initializer that supports Dictionary<String,AnyObject?>
But if I simply change AnyObject to an non-optional type, it works.
var dict: Dictionary <String, AnyObject?> = [
"title" : title as? AnyObject,
"date" : date as? AnyObject,
]
var jsonData: JSON = JSON(dict) // this is where I get the error
I need to actually a JSON data set that potentially has nil values, but it seems like SwiftyJSON doesn't allow it.
Is there any way I can create a JSON dictionary with optional objects using SwiftyJSON?
Neither any key nor any value of a Swift Dictionary can be nil.
You could declare the variable as optional
var dict: Dictionary <String, AnyObject>?

Swift: If I copy AnyObject that is JSON data, will the data be copied or passed by reference?

I get JSON data as a result of NSURLSession.sharedSession().dataTaskWithRequest and deserialize it to AnyObject:
var error: NSError?
let jsonObject: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments, error: &error)
I want to pass it to a completion handler for parsing jsonObject into structured data.
Question: will jsonObject be passed by reference or deep-copied? The question arises since Array and Dictionary that JSON consists of are value-type in Swift.
I found this answer to related question that says that objects inside Foundation are indeed NSArray and NSDictionary, i.e. reference types. Is it the same with JSON data?
Class objects (AnyObject) are always passed by reference.
JSON result data consists of NSArray and NSDictionary which are
reference-type. If you get result data into jsonObject which is
of type AnyObject? and you passed it in completion handler then
it will depends upon type of variable inside completion handler
that whether it will passed by refrence or deep values will copied.
If inside completion handler variable for catching jsonObject is
of type AnyObject then reference will passed and if completion
handler variable is of particular Array or Dictionary type
then it will deeply copied jsonObject's value.
Also one more thing is that if your completion handler variable is of particular type then you should know the JSON result format already otherwise it will not parsed properly.

Int does not conform to protocol 'StringLiteralConvertible'

Im trying to parse json in weather app, but have hit a snag that i cannot get past.
I do get an error, "Type 'int' does not conform to Protocol 'StringLiteralConvertible'" in the following code.
Ive tried casting the jsonResult["main"] but that does instead give the error "Operand of postfix should have optional type, type is AnyObject". Do i need to downcast the Array in some way and how, if so, should i do that?
I´ve searched so much for this but could not find any help in other posts. Code as follows.
func updateWeatherInfo(latitude: CLLocationDegrees, longitude: CLLocationDegrees) {
Alamofire.request(.GET, AlongRequest)
.responseJSON { (_, _, JSON, error) in
println(JSON)
self.updateUISuccess(JSON as NSArray!)
}
}
func updateUISuccess(jsonResult: NSArray) {
self.loading.text = nil
self.loadingIndicator.hidden = true
self.loadingIndicator.stopAnimating()
if let tempResult = ((jsonResult["main"] as NSArray)["temp"] as? Double)
This would be easier to give a definitive answer to if you provide the JSON that you're trying to parse, but the error message you're getting is clear.
That error is because you're trying to access what you've declared as an NSArray instance with a string subscript, twice in this one line:
if let tempResult = ((jsonResult["main"] as NSArray)["temp"] as? Double)
jsonResult is declared as an NSArray parameter, and then you're casting jsonResult["main"] to NSArray before trying to subscript it with ["temp"]. The problem here is that NSArray (and built-in Swift arrays) only use integer-based subscripting. The error is saying that where the Swift compiler is expecting an Int, you've provided a string literal.
To fix this, you'll need to go in one of two directions. If the structure you're trying to access actually has these string keys, then you should be using NSDictionary instead of NSArray in both cases. If not, and it's an integer-index array, you should be using integers.