I have a JSON file and I'm trying to access the array in it.
The JSON file looks like:
{
"cars": [{
"name": "BMW",
"icons": [["front.png", "back.png", "B3"],
["front_red", "back_red", "C4"]
]
}]
}
//cars is an array of dictionaries, I just mentioned one in the snippet.
I get the JSON data as:
func loadJSONData(){
if let path = Bundle.main.path(forResource: "testJSON", ofType: "json")
{
if let jsonData = NSData(contentsOfFile : path)
{
do {
if let jsonResult = try JSONSerialization.jsonObject(with: jsonData as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String:Any]
{
self.testJSONData = (jsonResult["cars"] as? Array)!
//self.testJSONData = (jsonResult["cars"] as? Array<Dictionary<String, Any>>)! //also tried this
}
}
catch let error as NSError {
print(error.localizedDescription)
}
}
}
}
testJSONData is declared as an array:
var testJSONData = [] as [Dictionary<String, Any>]
and the error occurs when trying to get the "icons" array from the JSON.
let namePredicate = NSPredicate(format: "name like BMW")
let filteredArray :Array = testJSONData.filter() { namePredicate.evaluate(with: $0) }
let carData: Dictionary = filteredArray[0] as Dictionary<String, Any>
let carIcons: Array = carData["icons"] as! Array //error at this line
Cannot convert value of type 'Array<_>' to specified type 'Array'
Can someone please show me where I'm doing wrong ? Thanks!
Array is a generic type in Swift, so when you want to declare an array variable, you always need to specific what type of elements the Array is holding. There's no such type as Array without specifying its Element type.
Also, there's no need for type annotations in Swift, the compiler can infer the types for you and you are explicitly telling the compiler the type by casting anyways.
carIcons should be of type Array<Array<String>> or as a shorthand [[String]]
let carIcons = carData["icons"] as! [[String]]
Some general comments about your code: don't use old Foundation types, such as NSData in Swift when they have native Swift equivalents. Also don't do force unwrapping of safe casted types, that makes no sense. Either handle the casting and unwrapping safely or simply force cast if you know the cast will succeed for sure. .mutableContainers have no effect in Swift, so don't use it. There's no need to cast error to NSError in a catch block, Swift has its own Error type.
func loadJSONData(){
if let fileURL = Bundle.main.url(forResource: "testJSON", withExtension: "json") {
do {
let jsonData = try Data(contentsOfFile: fileURL)
if let jsonResult = try JSONSerialization.jsonObject(with: jsonData) as? [String:Any], let cars = jsonResult["cars"] as? [[String:Any]] {
self.testJSONData = cars
} else {
print("Unexpected JSON format")
}
}
catch {
print(error)
}
}
}
However, if you are using Swift 4, the best solution would be using the type safe Codable protocol and JSONDecoder instead of JSONSerialization.
I have a json file
I need to get the latest "id": "article" "createdAt": "2016-04-22T03:38:39.130Z" date. How do I go about getting this data from the request in swift?
Note: Sorry im a swift newb.
let url = "https://cdn.contentful.com/spaces/maz0qqmvcx21/entries?access_token=ae8163cb8390af28cd3d7e28aba405bac8284f9fe4375a605782170aef2b0b48";
var jsonData:NSData?
do{
jsonData = try NSData(contentsOfURL: NSURL(string: url)!, options: NSDataReadingOptions.DataReadingUncached)
let jsonObject:AnyObject? = try NSJSONSerialization.JSONObjectWithData(jsonData!, options: NSJSONReadingOptions.AllowFragments)
if let itemArray = jsonObject?.objectForKey("items") as? NSArray{
for item in itemArray{
if let sysItem = item.objectForKey("sys"){
//this is createdAt
if let createdAt = sysItem.objectForKey("createdAt") as? String{
print("createdAt:\(createdAt)")
}
if let contentTypeItem = sysItem.objectForKey("contentType")!.objectForKey("sys"){
//this is id
if let id = contentTypeItem.objectForKey("id") as? String{
print("id:\(id)")
}
}
}
}
}
}catch let err as NSError{
print("err:\(err)")
}
This code dosen't use any libraries,but you can use SwiftyJSON,this is will be easy to parse json.
Hope this help.
This can be done in simple way. I am assuming that you have parsed your json to dictionary
You have a key with items which is an array of dictionary and inside that dictionary you have createdAt and id(well it is deeper into the hierarchy but I will show you how to get it) keys. You can access it by simply doing this.
for dict in jsonDict["items"] as! Array<NSDictionary> {
let sysDict = dict["sys"] as! NSDictionary
print(sysDict["createdAt"]) //prints all createdAt in the array
let contentDict = sysDict["contentType"]
print((contentDict["sys"] as! NSDictionary)["id"]) // prints all ids
}
Hope this helps.
I have declared a global variable 'var recipes = String: PFFile'.
On parse.com, I created a column called "recipe" of type File and i have uploaded .txt files that contain the recipes.
I am trying to load the contents of the .txt files from parse to a UITextView.
I have tried many things and this is what I have:
var recipes = [String: PFFile]()
var valueToPass: String!
var valuePassed: String!
var appetizer = [String]()
var images = [String: UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
let query = PFQuery(className: "Appetizers")
query.orderByAscending("recipe")
query.findObjectsInBackgroundWithBlock { (objects, error) in
guard error == nil, let objects = objects else {
print(error)
return
}
for object in objects {
// ... Appetizer Name
let appetizerName = object.objectForKey("appetizer") as! String
self.name.text = self.valuePassed
// ... Recipe
var recipes = [String: String]()
let recipeFile = object["recipe"] as! PFFile
do {
let recipeData = try recipeFile.getData()
let recipe = String(data: recipeData , encoding:NSUTF8StringEncoding)!
print(recipe) // recipe is now a string you can store or display
self.myTextView.text = recipe
} catch {
print("something went wrong")
}
// ... Image
let imageFile = object["imageFiles"] as!PFFile
imageFile.getDataInBackgroundWithBlock({ (imageData, error) -> Void in
if error == nil {
let data = imageData
} else {
print(error)
}
if let data = imageData {
self.images[appetizerName] = UIImage(data: data)
self.imageView.image = self.images[self.valuePassed]
}
})
}
}
}
I am able to display the recipe with the above code but not the one i chose. It is printing all the recipes in the logs but in a random order (but the same order each time) and the last one is the one being printed in the UITextView.
I can't seem to get the one i am choosing.
You create a dictionary recipes of type [string: PFFile]. Presumably this is to contain all the recipes returned by Parse. Then you never populate that dictionary.
Later down in your code you have this line:
let recipeFile = object["recipe"] as! PFFile
Is that the PFFile you want to add to your dictionary?
If so, then you could use code like this:
let someKey = //Whatever string key you want to use to store a recipe
recipes[someKey] = recipeFile
You say "I am trying to load the contents of the .txt files from parse to a UITextView. "
So you're trying to add the combined contents of all the text files into a single UITextView?
In that case you would need to change this line:
let recipe = String(data: recipeData , encoding:NSUTF8StringEncoding)!
Say you create a new var:
var allRecipesText = String()
Then you could add a line below the line that coverts a recipe to a String:
let recipe = String(data: recipeData , encoding:NSUTF8StringEncoding)!
//concatenate the new recipe string to the end of allRecipiesText
allRecipiesText += recipe
Do you really need to save the PFFile objects, or do you want to save the converted text? And do you really want your recipes in a dictionary, or would you rather have them in an array?
With this code, i was able to display the recipe i chose in the previous tableviewcontroller:
let recipeFile = object["recipe"] as! PFFile
do {
let recipeData = try recipeFile.getData()
let recipe = String(data: recipeData , encoding:NSUTF8StringEncoding)!
// recipe is now a string you can store or display
self.recipes[appetizerName] = recipe
self.myTextView.text = self.recipes[self.valuePassed]
} catch {
print("something went wrong")
}
appetizerName: used as the appetizer's name
valuePassed: chosen recipe in the tableview controller
I have two variable called "Countries" and "Places" and I'm trying to read a Data.plist and retrieve some values
This is the Data.plist:
Data.plist
I can't read the plist from the variables.
Let use as an example, the value of Countries is "Italia" and the value of Places is "Naples", how can I retrieve the two different values written in "Item 0" and "Item 1".
I've been searching for days in internet some tutorial who could help me but I couldn't make any of these working for my case (I used more tutorial examples but due my low reputation I can't post more than 2 links).
I tried to follow these tutorial:
Swift - searching through dictionaries in an array in a plist
http://sweettutos.com/2015/06/03/swift-how-to-read-and-write-into-plist-files/
I tried, for example, to use this code without use the "variables", but even this is not working:
let path = NSBundle.mainBundle().pathForResource("Dati", ofType: "plist")
let dict = NSDictionary(contentsOfFile: path!)
let value: AnyObject = (dict!.objectForKey("Italia")!.objectForKey("Naples")?.objectForKey("Item 0"))!
Can you please help me on this?
Thanks in advance.
This is a pure Swift solution using only Swift native types:
if let url = NSBundle.mainBundle().URLForResource("Dati", withExtension: "plist"), data = NSData(contentsOfURL: url) {
do {
let dictionary = try NSPropertyListSerialization.propertyListWithData(data, options: [], format: nil) as! [String:AnyObject]
if let city = dictionary["Italia"]?["Naples"] as? [AnyObject] {
let item0 = city[0] as! Int
let item1 = city[1] as! String
} else {
print("Italia or Naples doesn't exist")
}
} catch let error as NSError {
print("Property List Serialization Error: \(error)")
}
} else {
fatalError("File couldn't be read")
}
If you change the plist file to use only String values you can avoid some type casting
if let url = NSBundle.mainBundle().URLForResource("Dati", withExtension: "plist"), data = NSData(contentsOfURL: url) {
do {
let dictionary = try NSPropertyListSerialization.propertyListWithData(data, options: [], format: nil) as! [String:[String:[String]]]
if let city = dictionary["Italia"]?["Naples"] {
let item0 = city[0]
let item1 = city[1]
} else {
print("Italia or Naples doesn't exist")
}
} catch let error as NSError {
print("Property List Serialization Error: \(error)")
}
} else {
fatalError("File couldn't be read")
}
I have been reading some of the responses to questions with similar problems but I just can't figure it out...
I have PostService that does a JSON POST request and fetches the data from a MySQL database. Everything was working before I did the conversion to Swift 2.0 and now it's giving me gears. (Code comes from Skip Wilson's Youtube series - Swift: Using External Databases and API's)
It gives the above error in the output and stops and highlights this line -
"let response = (try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)) as! NSDictionary"
var settings:Settings!
init() {
self.settings = Settings()
}
let userLoginEmail = "admin#email.co.za";
let userLoginPassword = "1234";
func getPosts(callback:(NSDictionary) -> ()) {
request(settings.viewPosts, callback: callback)
}
func request(url:String, callback:(NSDictionary) -> ()) {
let myURL = NSURL(string: url)
let requested = NSMutableURLRequest(URL:myURL!);
requested.HTTPMethod = "POST";
let postString = "email=\(userLoginEmail)&password=\(userLoginPassword)";
print("email=\(userLoginEmail)&password=\(userLoginPassword)")
requested.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
let task = NSURLSession.sharedSession().dataTaskWithRequest(requested) {
(data, response, error) in
let response = (try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)) as! NSDictionary
callback(response)
}
task.resume()
}
Here's my JSON post... With my limited knowledge and reading up on json.org, it looks like an object with an array inside it containing a bunch of objects (A dictionary?) The format of all of this did not change and my app would fetch the data from the database and display it correctly before the conversion..
{"posts":[{"Post":{"Id":"5","idno":"4","product":"Aspen Simvastatin","quantity":"30","due_date":"2015-04-11","last_repeat":"2015-04-10","doctor":"Dr. Jim Jones","store":"Central","currentrepeat":"2","totalrepeat":"6","active_ingredient":"Simvastatin","strength":"20mg","manufacturer":"Aspen Pharmacare","dosage_form":"Tabs","directions":"Take one tablet daily","repeatflag":"0","repeattimestamp":"2015-08-17 20:38:13"}},{"Post":{"Id":"6","idno":"4","product":"Mybulen","quantity":"45","due_date":"2015-04-11","last_repeat":"2015-04-10","doctor":"Dr. Jim Jones","store":"Central","currentrepeat":"3","totalrepeat":"6","active_ingredient":"Codeine Phosphate;Ibuprofen;Paracetamol","strength":"10mg;200mg;250mg","manufacturer":"Aspen Pharmacare","dosage_form":"Tabs","directions":"Take one or two tablets four times a day after meals","repeatflag":"0","repeattimestamp":"2015-08-17 20:38:13"}},{"Post":{"Id":"7","idno":"4","product":"Ecotrin XL","quantity":"30","due_date":"2015-04-11","last_repeat":"2015-03-11","doctor":"Dr. Jim Jones","store":"Central","currentrepeat":"4","totalrepeat":"6","active_ingredient":"Aspirin","strength":"81mg","manufacturer":"Litha Pharma","dosage_form":"Tabs","directions":"Take one tablet in the morning","repeatflag":"0","repeattimestamp":"2015-08-17 20:38:13"}},{"Post":{"Id":"8","idno":"4","product":"Lorien","quantity":"28","due_date":"2015-04-11","last_repeat":"2015-03-11","doctor":"Dr. J. Eckel","store":"Central","currentrepeat":"4","totalrepeat":"6","active_ingredient":"Fluoxetine HCl","strength":"20mg","manufacturer":"Aspen Pharmacare","dosage_form":"Caps","directions":"Take one capsule in the morning","repeatflag":"0","repeattimestamp":"2015-08-17 20:38:13"}}]}
I would be extremely grateful for any help on this.
In my masterViewController's viewDidLoad(), I have this code which process the information fetched...
service = PostService()
service.getPosts {
(response) in
self.loadPosts(response["posts"]! as! NSArray)
}
}
func loadPosts(posts:NSArray) {
for post in posts {
let post = post["Post"]! as! NSDictionary
let Id = Int((post["Id"]! as! String))!
let idno = Int((post["idno"]! as! String))!
let product = post["product"]! as! String
let quantity = Int((post["quantity"]! as! String))!
let doctor = post["doctor"]! as! String
let store = post["store"]! as! String
let currentrepeat = Int((post["currentrepeat"]! as! String))!
let totalrepeat = Int((post["totalrepeat"]! as! String))!
let active_ingredient = post["active_ingredient"]! as! String
let strength = post["strength"]! as! String
let manufacturer = post["manufacturer"]! as! String
let dosage_form = post["dosage_form"]! as! String
let directions = post["directions"]! as! String
let postObj = Post(Id: Id, idno: idno, product: product, quantity: quantity, doctor: doctor, store: store, currentrepeat: currentrepeat, totalrepeat: totalrepeat, active_ingredient: active_ingredient, strength: strength, manufacturer: manufacturer, dosage_form: dosage_form, directions: directions)
postsCollection.append(postObj)
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
You are telling NSJSONSerialization that you are absolutely sure that the JSON can be parsed and that you want your app to crash if it doesn't. (That's the try! ). Well, there are plenty of situations where you are asking for JSON and you are getting html back, so your users won't be happy with that, let's say if they use your app in a hotel or at the nearest starbucks.
Next, you are telling NSJSONSerialization that you are absolutely sure that the JSON contains a dictionary, and that you want your app to crash if it doesn't (as! NSDictionary). Guess what, you were given an array. You better read the documentation for your API, and check what you are given here.
BTW. I don't care what you are posting what JSON you are supposedly getting - I know that you received an array. Don't believe it? First rule of debugging: What you know is wrong.