Combine Multiple NSMutableDictionary - swift

I have a recursive function that's adding the previous dictionary to the new dictionary but using addEntriesFromDictionary gives me error
Here's my sample code (EDITED)
func fetchAllSWApiList(strUrl: String, strArrayCallback: NSMutableDictionary){
let swApiHandler = SwApiHandler()
let url = strUrl
swApiHandler.requestSWPApi(url, completionHandler: {(response, error) in
if let responseDictionary = response as? Dictionary<String, AnyObject> {
print("Did Detect a dictionary")
strArrayCallback.addEntriesFromDictionary(responseDictionary)
}
guard let nextPage: String = response!["next"]! as? String else {
print("End Of Page")
print(strArrayCallback.description)
return
}
print(nextPage)
self.fetchAllSWApiList(nextPage, strArrayCallback: strArrayCallback)
})
}
If you have a better solution in my code that will return the combined list from the fetched data recursively the better.
EDIT: here's the error
NSDictionary is not implicitly convertible to '[NSObject: AnyObject]';
did you mean to use 'as' to explicitly convert?
after that my code will become should I leave it as it is or edit the NSpbject part?
strArrayCallback.addEntriesFromDictionary(response! as [NSObject : AnyObject])
EDIT2:
incase you're wondering what's the JSON model looks like here's a pic of it

You should cast your response to the Dictionary type that you're expecting, by doing something like:
if let responseDictionary = response as? Dictionary<String, AnyObject> {
strArrayCallback.addEntriesFromDictionary(responseDictionary)
}

Related

Json array Dictionary parse nil in swift 5

I have a json like bellow ..
{"type": "Polygon","coordinates":[[[90.40082675305842,23.708825220302813],[90.4018551231959,23.708188760430843],[90.40247361862504,23.7091957460091],[90.40143983815886,23.70975584674032],[90.40082675305842,23.708825220302813]]]}
I have used bellow code to parse which returns nil
let json = myjsonString as? [String: Any]
But it returns nil. please help me to parse above json
You have to deserialize the string, either with JSONSerialization or – more comfortable – with JSONDecoder
let jsonString = """
{"type": "Polygon","coordinates":[[[90.40082675305842,23.708825220302813],[90.4018551231959,23.708188760430843],[90.40247361862504,23.7091957460091],[90.40143983815886,23.70975584674032],[90.40082675305842,23.708825220302813]]]}
"""
struct Overlay : Decodable {
let type : String
let coordinates : [[[Double]]]
}
do {
let result = try JSONDecoder().decode(Overlay.self, from: Data(jsonString.utf8))
print(result)
} catch {
print(error)
}
At first, you need to convert data from your input string then you can convert data to dictionary object. You can try this example.
let jsonText = "{\"first_name\":\"Sergey\"}"
var dictonary:NSDictionary?
if let data = jsonText.data(using: String.Encoding.utf8) {
do {
dictonary = try JSONSerialization.jsonObject(with: data, options: []) as? [String:AnyObject]
if let myDictionary = dictonary {
print(" First name is: \(myDictionary["first_name"]!)")
}
} catch let error as NSError {
print(error)
}
}

Serializing JSON ReadingOptions with inconsistent output in Swift 4.2

I'm working on a pet project where I am serializing JSON using the JSONSerialization class and jsonObject(with:options:). The object is unusable until cast into a Dictionary [String: Any] or an Array [Any]. This is where the inconsistency occurs. The following is a method from one of my classes. The input is tested and valid.
private static func parse(data: Data) -> [JSONDictionary]? {
do {
let options = JSONSerialization.ReadingOptions() // rawValue = UInt 0
let otherOptions: JSONSerialization.ReadingOptions = [] // rawValue = UInt 0
let jsonAny = try JSONSerialization.jsonObject(with: data, options: otherOptions)
if let array = jsonAny as? [String: Any] {
print(array)
}
} catch {
return nil
}
return nil
}
Both of the ReadingOption objects are valid and produce valid output that can be properly cast, and print(array) is called.
However, when I use the following, invalid output is returned and can not be cast properly. Note options in the jsonObject call has an equivalent value to otherOptions in the above example.
private static func parse(data: Data) -> [JSONDictionary]? {
do {
let jsonAny = try JSONSerialization.jsonObject(with: data, options: [])
if let array = jsonAny as? [String: Any] {
print(array) // never called
}
} catch {
return nil
}
return nil
}
I thought because they have equivalent values that I could use them in place of each other. But that is not the case. Is this a bug, or am I using this incorrectly?
Edit: here is the dataset being used https://www.govtrack.us/api/v2/role?current=true&role_type=senator
The reading options are irrelevant. In Swift ReadingOptions are only useful if the expected result is not array or dictionary.
If the expected type is array or dictionary omit the options parameter.
The inconsistency is that your return type is an array ([JSONDictionary]) but the actual type is a dictionary.
private static func parse(data: Data) -> JSONDictionary? {
do {
let jsonAny = try JSONSerialization.jsonObject(with: data)
if let jsonDictionary = jsonAny as? JSONDictionary {
return jsonDictionary
}
} catch {
print(error)
return nil
}
return nil
}
It's recommended to hand over an error of a throwing method
enum SerializationError : Error {
case typeMismatch
}
private static func parse(data: Data) throws -> JSONDictionary {
let jsonAny = try JSONSerialization.jsonObject(with: data)
guard let jsonDictionary = jsonAny as? JSONDictionary else { throw SerializationError.typeMismatch }
return jsonDictionary
}

Getting nil value when read JSON data in Swift

if let postString = NSString(data:data!, encoding: NSUTF8StringEncoding) as? String {
guard let jsonData = postString.dataUsingEncoding(NSASCIIStringEncoding) else {
fatalError()
}
guard let jsonObjects = try? NSJSONSerialization.JSONObjectWithData(jsonData,options: [])
,let JSONArray = jsonObjects as? [[String: AnyObject]]
else {
fatalError()
}
print(JSONArray)
}
In postString constant, I am getting "[{\"Name\":\"ABC\",\"Age\":35},{\"Name\":\"CDE\",\"Age\":36‌​}]"
and when I run this code then fatalError() code call.
A couple of other people have explained what you did wrong in this case (Tried to cast the output of deserialization to a dictionary when it actually contains an array.)
Stepping back from the details, when something fails, you need to break your code into smaller pieces and then trace through it to see what's failing.
The "as?" cast says "Try to cast this object to another type. Wrap the results in an Optional." If the cast fails, the result is nil. If it succeeds, the optional contains the new type.
If you rewrote your code as:
let jsonObject = try NSJSONSerialization.JSONObjectWithData(data!,
options: NSJSONReadingOptions.AllowFragments)
guard let jsonDict = jsonObject as [String: Any] else {
print("Cast failed")
return
}
Then the print statement would fire and you'd know that the cast was the problem.
EDIT:
I just noticed that your JSON data contains an array of dictionaries of type [String: Int]. In Swift Ints are not an Object type, so you need to cast your results to [[String:Any]], not [[String:AnyObject]]. I've fixed my code above.
I Wrote the following code in a playground and it works:
let jsonString = "[{\"Name\":\"ABC\",\"Age\":35},{\"surveyName\":\"CDE\",\"Age\":36}]"
guard let jsonData = jsonString.data(using: .ascii) else {
fatalError()
}
guard let jsonObjects = try? JSONSerialization.jsonObject(with: jsonData, options: []),
let JSONArray = jsonObjects as? [[String: Any]]
else {
fatalError()
}
print(String(describing: jsonObjects))
It gives the output:
(
{
Age = 35;
Name = ABC;
},
{
Age = 36;
surveyName = CDE;
}
)
Which is what I would expect.
EDIT #2:
Actually, on further investigation I'm stumped as to why your code isn't working. I just tested it, and the as [[String: AnyObject]] works. It turns out that in Swift 3 if you cast an Int to AnyObject and you've included Foundation (or UIKit) then it gets silently converted to an NSNumber, which IS an Object type.
You're going to need to show your actual JSON data and the code that converts it to an object if you need help debugging it.
EDIT #3:
Below is code I wrote and tested in Swift 2.3:
func parseJSONTest() {
let jsonString = "[{\"Name\":\"ABC\",\"Age\":35},{\"surveyName\":\"CDE\",\"Age\":36}]"
guard let jsonData = jsonString.dataUsingEncoding(NSASCIIStringEncoding) else {
fatalError()
}
//I'm not sure why you take JSON data, convert it to a string, and convert
//It back to NSData, but to prove a point, this is your code being fed
//well-formed JSON data in an NSData object:
if let postString = NSString(data:jsonData,
encoding: NSASCIIStringEncoding) as? String {
guard let jsonData = postString.dataUsingEncoding(NSASCIIStringEncoding) else {
fatalError()
}
guard let jsonObjects = try? NSJSONSerialization.JSONObjectWithData(jsonData,options: []),
let JSONArray = jsonObjects as? [[String: AnyObject]]
else {
fatalError()
}
print(JSONArray)
}
}
In order to provide a complete test I first take a string containing JSON data and convert it to NSData. I then convert that NSData back to JSON objects and cast them to the desired type, and it works. The code above displays:
[["Name": ABC, "Age": 35], ["surveyName": CDE, "Age": 36]]
Which matches the structure you have (an array of dictionaries).
The above is technically not an json object it is a json array.
Try casting as [AnyObject] instead of [String: AnyObject]
Then use the array to access the item you need. Then cast that to
[String:AnyObject]
because they are json objects within a json array

Swift 3 and Xcode 8.2 - Ambiguous reference to member 'Subscript'

I get a error and I do not know why ... can anyone help me? I am despairing!
No other post has helped me. Thank you very much in advance for your answer!!
PS: I get the error only when I try to run on my own iphone
Image with Error
func parseJson() {
let username: String = UserDefaults.standard.value(forKey: "username")! as! String
let url=URL(string:"https://website.de")
do {
let allBetData = try Data(contentsOf: url!)
let allBet = try JSONSerialization.jsonObject(with: allBetData, options: JSONSerialization.ReadingOptions.allowFragments) as! [String : AnyObject]
if let arrJSON = allBet["bets"] as! [String : AnyObject]? {
for index in 0...arrJSON.count-1 {
let aObject = arrJSON[index] as [String : AnyObject]?
header.append(aObject["header"] as! String)
rowDescription.append(aObject["rowDescription"] as! String)
bodytext.append(aObject["bodytext"] as! String)
}
}
print("data loaded")
self.tableView.reloadData()
}
catch {
self.logout()
}
}
Ok, this is totally fundamental and you need to make sure you get this.
One line at a time...
if let arrJSON = allBet["bets"] as! [String : AnyObject]? {
Here you say, "I am making this thing called arrJSON, it's a dictionary with string keys and any sort of value". Good so far? Then you...
for index in 0...arrJSON.count-1 {
"I would like to loop the number of times that there are items"...
let aObject = arrJSON[index] as [String : AnyObject]?
"...and get the object who's key is this number".
Do you understand the problem now?

Why I can't assign string data to my nsuserdefaults in Swift?

I have a call to my webservice and it fetches 3 string values, I want to store them for good, so I thought about using nsuserdefaults. This is my code for that:
var username = json["id"]
var googleUserId = json["g_username"]
var facebookUserId = json["f_username"]
NSUserDefaults.standardUserDefaults().setObject(username, forKey: "username")
NSUserDefaults.standardUserDefaults().setObject(googleUserId, forKey: "googleUserId")
NSUserDefaults.standardUserDefaults().setObject(facebookUserId, forKey: "facebookUserId")
NSUserDefaults.standardUserDefaults().synchronize()
The error I'm getting says:
Cannot convert value of type 'JSON' to expected argument type 'AnyObject?'
What's the problem here?
==== EDIT
sorry for not mentioning that before - the json variable comes from alamofire response, this is how it looks in my code:
Alamofire.request(.POST, "http://mywebservice", parameters: par) .response {
(request, response, data, error) in
if(error == nil){
var json = JSON(data: data!)
You're using SwiftyJSON, so you should also use SwiftyJSON's features. :)
There's no need to "downcast" dictionary results with SwiftyJSON, it's already done!
Each SwiftyJSON object has optional getters and non-optional getters.
You have a field with a string as a result? Use .string:
if let username = json["id"].string {
defaults.setObject(username, forKey: "username")
}
For integers it would be .int, for arrays it is .array, etc.
There's also the non-optional getters, they have the word "Value" added to the property:
let username = json["id"].stringValue
defaults.setObject(username, forKey: "username")
But warning! A non-optional getter will assume that the value is here and force-unwrap, so if it's nil, it will crash: json["id"].stringValue is the same as json["id"].string!.
When you do this:
var username = json["id"]
You do not get back a String. You get a JSON object. If you know it is a string, then cast it.
var username = json["id"] as! String
if let username = json["id"] as! String {
// it is not nil
}
else {
// it is nil
}
Try this code, it's crash safe
let defaults = NSUserDefaults.standardUserDefaults()
if let username = json["id"] as? String {
defaults.setObject(username, forKey: "username")
}
if let googleUserId = json["g_username"] as? String {
defaults.setObject(googleUserId, forKey: "googleUserId")
}
if let facebookUserId = json["f_username"] as? String {
defaults.setObject(facebookUserId, forKey: "facebookUserId")
}
defaults.synchronize()
Try this:
Alamofire.request(.POST, "http://mywebservice", parameters: par).responseJSON {
request, response, result in
switch result {
case .Success(let data):
let json = JSON(data: data)
// ...
case .Failure(let data, let error):
print("Request failed with error: \(error)")
}
}