I have trouble with the NSJSONSeralization.dataWithJSONObject.
This will make my application crash:
#IBAction func sendMessage(sender: AnyObject) {
cachedMessage = messageField.text
messageField.text = ""
let messageData = NSJSONSerialization.dataWithJSONObject(cachedMessage, options: NSJSONWritingOptions.PrettyPrinted, error: nil)
...
}
I hope you can somehow help me...
It will give you an error like : Invalid top-level type in JSON write
If you are trying to create a JSON object then it should be either from Array or Dictionary. Because An object that you want convert in to JSON Must be a Top Level object.
The top level object is an NSArray or NSDictionary.
Try in this way :
var demoArray : NSArray! // (Use it if you want to send data as an Array)
var demoDic : NSDictionary! // (Use it if you want to send data as an Dictionary (Key - Value Pair))
var cachedMessage : String!
cachedMessage = "Sample" // Here your String From textfield
demoArray = [cachedMessage] // Array with your string object
demoDic = ["Your Key":cachedMessage] // Dic with your string object.
You can provide your desired key instead of Your Key
This is how you can create Data from array and Dictionary.
let msgDataOfArray = NSJSONSerialization.dataWithJSONObject(demoArray, options: NSJSONWritingOptions.PrettyPrinted, error:nil)
let msgDataOfDic = NSJSONSerialization.dataWithJSONObject(demoDic, options: NSJSONWritingOptions.PrettyPrinted, error: nil)
If you want to see how your data will look after JSONSerialization process then you can see like below way
var DataToStringForArray = NSString(data: msgDataOfArray!, encoding: NSUTF8StringEncoding)
var DataToStringForDic = NSString(data: msgDataOfDic!, encoding: NSUTF8StringEncoding)
println("Data To String OF Array : \(DataToStringForArray)")
println("Data To String OF Dic : \(DataToStringForDic)")
Related
I make a API request with Alamofire , I then get a response in JSON format, I then parse the JSON into a NSDictionary to get to the data I want.
The data I get is four Arrays of different items.
I want to the create a new List in Realm to save these items in.
Here are my Realm Object Classes :
class ListOfDefinitions: Object {
let listOfItems = List<Item>()
}
and
class Item: Object {
dynamic var AverageCost = Int()
dynamic var Barcode = ""
dynamic var Description = ""
dynamic var InternalUnique = Int()
dynamic var LastCost = Int()
dynamic var LimitToMainRegionUnique = Int()
dynamic var Notes = ""
dynamic var StockCategoryUnique = Int()
dynamic var StockCode = ""
dynamic var StockGroupUnique = Int()
dynamic var UnitDescriptor = ""
}
Here is my code on how I handle the JSON response and where I want to save the data in my code.
var newItemInStockList : ListOfDefinitions! // declared in the class
let newItemInStock = Item()
.responseJSON { response in
switch response.result {
case .Success(let JSON):
// print("Success with JSON: \(JSON)")
let response = JSON as! NSDictionary
let responseParams = response.objectForKey("ResponseParameters") as! NSDictionary
//print(responseParams)
//let stockItemGroupList = responseParams.objectForKey("StockItemGroupList")
let stockItemList = responseParams.objectForKey("StockItemList") as! NSDictionary
//print(stockItemList)
let listofDefinitions = stockItemList.objectForKey("ListofDefinitions") as! NSArray
print(listofDefinitions.count)
for defJson in listofDefinitions {
print(defJson["Description"])
someString = defJson["Description"] as! String
print(someString)
// Because there are 4 arrays of items this for loop will be red 4 times, each time it is red I want o create a new list and add the items to the list
// This comment area is where I tried to create a new list and then .append the items in it, but it doesn't work.
// let newOne = ListOfDefinitions()
//
//
// try! realm.write{
//
// realm.add(newOne)
// }
// self.newItemInStock.AverageCost = defJson["AverageCost"] as! Int
// self.newItemInStock.Barcode = defJson["Barcode"] as! String
// self.newItemInStock.Description = defJson["Description"] as! String
// self.newItemInStock.InternalUnique = defJson["InternalUnique"] as! Int
// self.newItemInStock.LastCost = defJson["LastCost"] as! Int
// self.newItemInStock.LimitToMainRegionUnique = defJson["LimitToMainRegionUnique"] as! Int
// self.newItemInStock.Notes = defJson["Notes"] as! String
// self.newItemInStock.StockCategoryUnique = defJson["StockCategoryUnique"] as! Int
// self.newItemInStock.StockCode = defJson["StockCode"] as! String
// self.newItemInStock.StockGroupUnique = defJson["StockGroupUnique"] as! Int
// self.newItemInStock.UnitDescriptor = defJson["UnitDescriptor"] as! String
//
// try! realm.write{
//
// self.newItemInStockList.listOfItems.append(self.newItemInStock)
// }
}
case .Failure(let error):
print("Request failed with error: \(error)")
}
And here is what I get when I print the 4 Arrays
Looking at your sample code, I think the main issue happening here is that you're re-using the same self.newItemInStock instance for each object you're adding to the list.
It would be best to create a new Item object in the loop as you're going along and append that to the List object.
I recommend using a combination of AlamofireObjectMapper to handle all your JSON mapping (both ways) https://github.com/tristanhimmelman/AlamofireObjectMapper
and the ListTransform found in ObjectMapper+Realm https://github.com/Jakenberg/ObjectMapper-Realm
They're both available to be installed through cocoapods. Your code will look much cleaner and easier to maintain
I need to parse JSON file. Here is my getJSON func
public var shops: NSArray = []
public func getShop() {
let url = NSURL (string: "http://urltojson.com")
let data = NSData (contentsOfURL: url!)
shops = try! NSJSONSerialization.JSONObjectWithData(data!,options: .AllowFragments) as! NSArray
}
and here is how I get data from JSON
override func viewDidLoad() {
let test = shops ["Titile"] as? String
print(test)
}
The problem is when I run my code it shows me an error "Cannot convert value of type 'String' to expected argument type Int"
so, If I change ["Titile"] in let test = shops ["Titile"] for any Int, e.g. [8] let test = shops [8] as? String it works.
What did I do wrong?
looks like your variable "shops" is an array which takes an index as an integer instead of a dictionary which takes a key as a String.
//here shops is an array of strings
var shops:[String] = ["dog","cat","pig","cow"]
//shops[2] is equal to "pig"
//here shops is a dictionary of string keys and string values
var shops:[String:String] = ["animal1":"dog","animal2":"cat","animal3":"pig","animal4":"cow"]
//shops["animal2"] is equal to "cat"
I'm Having trouble with JSON and Swift 2.
I'm getting this Array from the server
[{"KidName":"Jacob","KidId":1,"GardenID":0},
{"KidName":"Sarah","KidId":2,"GardenID":0},
{"KidName":"Odel","KidId":3,"GardenID":0}]
I'm familiar with JSON and I know it's not the recommended way to get a JSON, since it's supposed to be something like
{"someArray":[{"KidName":"Jacob","KidId":1,"gardenID":0}, .....
So my first question is it possible to run over the first JSON I've post and get the KidName number without editing the JSON and Add to it a JSON OBJECT to hold the array ?
my second question is really with Swift 2, how can I get the KidName (after I've edited the JSON to have an holder for the array)?
this is my code... (please read the Notes I've added)
BTW, I'm familiar with SwiftyJSON as well...
// Method I've build to get the JSON from Server, the Data is the JSON
sendGetRequest { (response, data ) -> Void in
// need to convert data to String So I can add it an holder
if let str = NSString(data: data, encoding: NSUTF8StringEncoding) as? String {
/**
after editing the str, i'm Having a valid JSON, let's call it fixedJSON
*/
let fixedJSON = "{\"kidsArray\":\(dropLast)}"
// Now I'm converting it to data back again
let jsonTodata = fixedJSON.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
// After Having the data, I need to convert it to JSON Format
do{
let dataToJson = try NSJSONSerialization.JSONObjectWithData(jsonTodata, options: []) as! [String:AnyObject]
//Here I'm getting the KidID
if let kidID = jsonSe["kidsArray"]![0]["KidId"]!!.integerValue {
print("kidID in first index is: \(kidID)\n")
}
//NOW trying to get the KidName which not working
if let kidname = jsonSe["kidsArray"]![0]["KidName"]!!.stringValue {
print("KidName is \(kidname)\n")
}
}
So as you can see, I'm not able to get the KidName.
Any Help Would be Appreciate.
You can use the following function to get the 'someArray' array and then use this getStringFromJSON function to get the 'KidName' value.
func getArrayFromJSON(data: NSDictionary, key: String) -> NSArray {
if let info = data[key] as? NSArray {
return info
}
else {
return []
}
}
let someArray = self.getArrayFromJSON(YourJSONArray as! NSDictionary, key: "someArray")
func getStringFromJSON(data: NSDictionary, key: String) -> String {
if let info = data[key] as? String {
return info
}
return ""
}
let KidName = self.getStringFromJSON(someArray as! NSDictionary, key: "KidName")
Hope this might be useful to you.
I'm new to Swift - trying to read a JSON file from a URL. My attempt below.
The JSON looks valid - I tested it with JSONLint but it keeps crashing.
Thoughts?
func getRemoteJsonFile() -> NSDictionary {
//Create a new url
let remoteUrl:NSURL? = NSURL(string: "http://nfl-api.azurewebsites.net/myplayers.json")
//check if its nil
if let actualRemoteUrl = remoteUrl {
//try to get the data
let filedata:NSData? = NSData(contentsOfURL: actualRemoteUrl)
//check if its nil
if let actualFileData = filedata {
//parse out the dictionaries
let jsonDict = NSJSONSerialization.JSONObjectWithData(actualFileData, options: NSJSONReadingOptions.AllowFragments, error: nil) as NSDictionary
return jsonDict
}
}
return NSDictionary()
}
This took me a second to figure out, so I don't blame you for missing it.
The JSON you linked to is minified, so it's difficult to see the structure. Let's take a look at (a fragment of) it after piping it through a prettifier:
[
{
"PlayerId":2501863,
"PlayerName":"Peyton Manning",
"PlayerTeam":"DEN",
"PlayerPosition":"QB",
"PlayerPassingYards":4727,
"PlayerPassingTDs":39,
"PlayerInterceptions":15,
"PlayerRushingYards":-24,
"PlayerRushingTDs":0,
"PlayerReceivingYards":0,
"PlayerReceivingTDs":0,
"PlayerReturnYards":0,
"PlayerReturnTDs":0,
"PlayerFumbleTDs":0,
"PlayerTwoPointConversions":2,
"PlayerFumblesLost":2,
"PlayerTeamLogo":"http://i.nflcdn.com/static/site/7.0/img/logos/teams-gloss-81x54/den.png"
}
]
Huh. It's encased in brackets, which means that it's an array.
It's an array, so you can't cast it as an NSDictionary. Instead, you could cast it as an NSArray, but why not use native Swift types?
Well, if you don't like types, you're about to find out, but I still think that this is a better way, because it forces you to think about the data you're parsing.
So we have the first part of our type definition for this function; it's an array ([]). What components is our array made up of? We could go with a simple NSDictionary, but we're doing full native types here, so let's use a native Swift dictionary.
To do that, we have to know the types of the dictionary (the syntax for a native dictionary type is [KeyType: ValueType]). Examining the JSON shows that all of the keys are Strings, but the values are of varying types, so we can use AnyObject.
That gives us a dictionary type of [String: AnyObject], and our entire JSON is an array of that, so the final type is [[String: AnyObject]] (wow).
Now that we have the proper type, we can modify the function you're using to parse the JSON a bit.
First of all, let's use our new type for the return and cast values. Then, let's make the return type optional in case something goes wrong and add an error variable to document that.
A cleaned up function would look something like this:
func getData() -> [[String: AnyObject]]? {
let data: NSData? = NSData(contentsOfURL: NSURL(string: "http://nfl-api.azurewebsites.net/myplayers.json")!)
if let req: NSData = data {
var error: NSError?
if let JSON: [[String: AnyObject]] = NSJSONSerialization.JSONObjectWithData(req, options: NSJSONReadingOptions.AllowFragments, error: &error) as? [[String: AnyObject]] {
return JSON
}
}
return nil
}
That's it!
We can now call the function and extract values from our [[String: AnyObject]] (again, wow) like this:
if let data: [[String: AnyObject]] = getData() {
println(data[0]["PlayerName"]!) // Peyton Manning
}
Update your code with this:
func getRemoteJsonFile() -> [NSDictionary] {
// Create a new URL
let remoteUrl:NSURL? = NSURL(string: "http://nfl-api.azurewebsites.net/myplayers.json")
let urlString:String = "\(remoteUrl)"
// Check if it's nil
if let actualRemoteUrl = remoteUrl {
// Try to get the data
let fileData:NSData? = NSData(contentsOfURL: actualRemoteUrl)
// Check if it's nil
if let actualFileData = fileData {
// Parse out the dictionaries
let arrayOfDictionaries:[NSDictionary]? = NSJSONSerialization.JSONObjectWithData(actualFileData, options: NSJSONReadingOptions.MutableContainers, error: nil) as [NSDictionary]?
if let actualArrayOfDictionaries = arrayOfDictionaries {
// Successfully parsed out array of dictionaries
return actualArrayOfDictionaries
}
}
}
return [NSDictionary]()
}
This is working fine for me.
For backend communication, my app requires a method to create a certainly structured JSON, and thats where i struggle.
The created JSON is supposed to look like this:
{
"data": {
"color":"yellow",
"size":"big"
}
}
Serializing a Dictionary with the required Data does not really seem to have the option to format the content properly, my best results look like this:
Optional({
Kategorie = Strassenschaeden;
PLZ = 46282;
Strasse = Erftweg;
Unterkategorie = Schlagloch;
})
I didnt find any helpful weblinks for my problem, and since im new to Swift and its documentation Im kinda stuck at the moment.
So my questions are:
Whats the preferred data structure for my JSON data (Dictionary/Array) and how do I create a JSON that is well-formated?
Thanks in advance :)
Edit: This is the interesting part of what i have used to achieve my "best result":
var data: [String: String] = ["Kategorie": "\(Kategorie)", "Unterkategorie": "\(Unterkategorie)", "Strasse": "\(Strasse)","PLZ": "\(PLZ)"]
self.post(data, url: "http://*************") { (succeeded: Bool, msg: String) -> () in
var alert = UIAlertView(title: "Success!", message: msg, delegate: nil, cancelButtonTitle: "Okay.")
func post(params : Dictionary<String, String>, url : String, postCompleted : (succeeded: Bool, msg: String) -> ()) {
var request = NSMutableURLRequest(URL: NSURL(string: url)!)
let JSONData:NSData = NSJSONSerialization.dataWithJSONObject(params, options: NSJSONWritingOptions.PrettyPrinted, error: &err)!
var json = NSJSONSerialization.JSONObjectWithData(JSONData, options: nil, error: &err) as? NSDictionary
println(json)
Here
let JSONData:NSData = NSJSONSerialization.dataWithJSONObject(params, options: NSJSONWritingOptions.PrettyPrinted, error: &err)!
var json = NSJSONSerialization.JSONObjectWithData(JSONData, options: nil, error: &err) as? NSDictionary
you are converting the params dictionary to JSON data – and then you convert the
JSON data back do a dictionary! What you probably want is to create a string
from the JSON data:
let jsonData = NSJSONSerialization.dataWithJSONObject(params, options: .PrettyPrinted, error: &err)!
let json = NSString(data: jsonData, encoding: NSUTF8StringEncoding)!
println(json)
Remarks:
Properties and variables should have names starting with lower case letters, e.g.
jsonData.
The explicit type annotation :NSData is not needed here, the Swift compiler can
infer the type automatically.
The option can be given as .PrettyPrinted instead of NSJSONWritingOptions.PrettyPrinted, the compiler infers the enumeration type
automatically.
Instead of forced unwrapping with ! you should use optional binding to check
for success.
Just an itch, that no one here recommend swiftyJSON for working with JSON in Swift.
Try it, you will lose your pain of dealing with JSON.
https://github.com/SwiftyJSON/SwiftyJSON
To Read JSON
let jsonData = jsonString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let jsonObject = JSON(data: jsonData!)
To Write JSON
let jsonString = jsonObject.rawString()