func jsonParsing1(){
do{
let path : NSString = NSBundle.mainBundle().pathForResource("fileName", ofType: "json")!
let data : NSData = try! NSData(contentsOfFile: path as String, options: NSDataReadingOptions.DataReadingMappedIfSafe)
let jsonData = try! NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers)
let jsonArray = jsonData
** let templeArray = (jsonArray.valueForKey("temple-name") as? NSArray)!**
}catch {
print(error)
}
}
}
my json files is
[
{
“temple-name”: "aaa",
“image”: "image.png”,
“description”: “aaa“
},
{
“temple-name”: "bbb",
“image”: "image1.png”,
“description”: “bbb“
}
]
I am using json file in a separate class and trying to access the parsed array all through the project.
Used global array but it returns nil when calling from another class. Thanks in advance.
I need to use the templeArray globally.
You can create a singleton class with templeArray property, store the value in this array and access it through shared instance of the singleton class.
Or,
You can declare templeArray property in appDelegate and global access to it.
You can static variables to access data across your project.
class GlobalVariables {
static var templeArray : NSMutableArray?
}
You can use templeArray throughout your application via
GlobalVariables.templeArray?.objectAtIndex(index)
This code should work:
var templeArray: NSMutableArray = []
class Parser {
func jsonParsing1() {
do {
let path : NSString = NSBundle.mainBundle().pathForResource("fileName", ofType: "json")!
let data : NSData = try NSData(contentsOfFile: path as String, options: NSDataReadingOptions.DataReadingMappedIfSafe)
let jsonData = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers)
let jsonArray = jsonData
if let rawTempleArray = jsonArray.valueForKey("temple-name") as? NSMutableArray {
templeArray = rawTempleArray
} else {
print("temple-name is not array")
}
} catch {
print(error)
}
}
}
I would do like this:
struct Temple { //or class
// your fields here
init? (templeDictionary: NSDictionary) {
// your parser here
}
}
class TheParser {
static var theTempleArray: [Temple] = []
func jsonParsing1() {
do {
let path : NSString = NSBundle.mainBundle().pathForResource("fileName", ofType: "json")!
let data : NSData = try NSData(contentsOfFile: path as String, options: NSDataReadingOptions.DataReadingMappedIfSafe)
let jsonData = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers)
let jsonArray = jsonData
if let rawTempleArray = jsonArray.valueForKey("temple-name") as? NSArray {
for temple in rawTempleArray {
if let theTemple = temple as? NSDictionary { // or NSArray or String depending of your json structure
if let templeItem = Temple(templeDictionary: theTemple) {
TheParser.theTempleArray.append(templeItem)
}
}
}
} else {
print("temple-name is not array")
}
} catch {
print(error)
}
}
}
Please try this kind of approach:
class MyClass {
static var templeArray : NSArray?
func jsonParsing1(){
let path : NSString = NSBundle.mainBundle().pathForResource("fileName", ofType: "json")!
let data : NSData = try! NSData(contentsOfFile: path as String, options: NSDataReadingOptions.DataReadingMappedIfSafe)
let jsonData = try! NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers)
let jsonArray = jsonData
MyClass.templeArray = (jsonArray.valueForKey("temple-name") as? NSArray)!
/*
* You can now access to templeArray in this way:
* let myArray : NSArray? = MyClass.templeArray
*/
}
}
In addition, the do/catch block is useless in Swift2.
EDIT:
You are doing it wrong.
let templeArray = (jsonArray.valueForKey("temple-name") as? NSArray)!
will always be nil because the field temple name isn't an array, it is a string.
You have to do:
MyClass.templeArray = jsonArray
Then you can access the first temple this way:
let temple = MyClass.templeArray[0]
let templeName : String = temple.objectForKey("temple-name") as? String
Related
I have created a property list with continents, countries, and random facts as shown below:
I can access the top level keys from the property list easily enough:
if let path = NSBundle.mainBundle().pathForResource("countryData", ofType: "plist") {
dict = NSDictionary(contentsOfFile: path)
}
countries += dict!.allKeys as! [String]
If I wanted to access the second element in the vanuatu array, however, things fall apart. I would think objectForKey would get the country dictionary and then use objectForKey again to get the country array. But so far, that hasn't worked. At all...
if let path = NSBundle.mainBundle().pathForResource("countryData", ofType: "plist") {
dict = NSDictionary(contentsOfFile: path)
if let australia = dict["australia"] as? [String:AnyObject]{
// access the second element's property here
if let vanuatu = australia["vanuatu"] as? [String]{
// Access the vanuatu here
}
}
}
if let path = NSBundle.mainBundle().pathForResource("Property List", ofType: "plist") {
dict = NSDictionary(contentsOfFile: path)
if let vanuatu = dict.objectForKey("australia") as? [String:AnyObject]{
if let vanuatuArray = vanuatu["vanuatu"] as? [String]{
print(vanuatuArray[1])
}
}
}
You can get data from plist file like that.
I have created a plist file for countryCodes.
func fetchCounrtyCodes() -> [CountryCodes]{
let name = "name"
let dial_code = "dial_code"
let code = "code"
var countryArray = [CountryCodes]()
guard let filePath = NSBundle.mainBundle().pathForResource("CountryList", ofType: "json") else {
print("File doesnot exist")
return []
}
guard let jsonData = NSData(contentsOfFile: filePath) else {
print("error parsing data from file")
return []
}
do {
guard let jsonArray = try NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.AllowFragments) as? [[String:String]] else {
print("json doesnot confirm to expected format")
return []
}
countryArray = jsonArray.map({ (object) -> CountryCodes in
return CountryCodes(name: object[name]!, dial_code:object[dial_code]!, code: object[code]!)
})
}
catch {
print("error\(error)")
}
return countryArray
}
struct CountryCodes{
var name = ""
var dial_code = ""
var code = ""
}
let urlAsString = "https://drive.google.com/uc?export=download&id=0B2bvUUCDODywWTV2Q2IwVjFaLW8"
let url = NSURL(string: urlAsString)!
let urlSession = NSURLSession.sharedSession()
let jsonQuery = urlSession.dataTaskWithURL(url, completionHandler: { data, response, error -> Void in
do {
if let jsonDate = data, let jsonResult = try NSJSONSerialization.JSONObjectWithData(jsonDate, options: []) as? NSDictionary {
print(jsonResult)
}
} catch let error as NSError {
print(error)
}
})
jsonQuery.resume()
Okay so here i am receiving data from online json then storing it as NSDictionary in jsonresult . I need to get all keys and values as into two separate arrays ?
Basically i want this
jsonresult.allkeys --> String array
jsonresult.allvalues --> String array
You can use:
let keys = jsonResult.flatMap(){ $0.0 as? String }
let values = jsonResult.flatMap(){ $0.1 }
It is quite simple because you are using jsonResult as NSDictionary.
let dict: NSDictionary = ["Key1" : "Value1", "Key2" : "Value2"]
let keys = dict.allKeys
let values = dict.allValues
In you're case
let keys:[String] = dict.allKeys as! [String]
var values:[String]
if let valuesSting = dict.allValues as? [String] {
values = valuesSting
}
For anyone trying it with newer version Swift please use compactMap()instead of flatMap()
let keys = jsonResult.compactMap(){ $0.0 as? String }
let values = jsonResult.compactMap(){ $0.1 }
I am trying to parse some json data into three different arrays based off the label in the json. I seem to be stuck and don't know why my for loop is never being entered. I am new to iOS and am using this to learn swift. Any help will be appreciated.
Here is the code that I am using:
var myPicture = [String]()
var myPath = [String]()
var mylabel = [String]()
let jsonString = "[{\"picture\" : \"Picture 1 \", \"path\": \"Path 1\" , \"label\" : \"Label 1\"}]"
//Convert jsonString to NSData
let myData = jsonString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
do{
let promoJson = try NSJSONSerialization.JSONObjectWithData(myData, options:.AllowFragments)
if let promtions = promoJson[""] as? [[String: AnyObject]] {
for promtions in promtions {
if let picture = promtions["picture"] as? String
{
myPicture.append(picture)
if let path = promtions["path"] as? String
{
myPath.append(path)
if let label = promtions["label"] as? String
{
mylabel.append(label)
}
}
}
}
}
}catch {
print("Error with Json: \(error)")
}
print(myPicture.first)
print(myPath.first)
print(mylabel.first)
The results for the print are all nil. So nothing is being appended to the arrays
The if let promtions = promoJson[""] part won't work and would be useless anyway. This is only promoJson that you have to cast to an array of dictionaries.
You weren't that far from the solution, look at my working version of your code:
do {
let promoJson = try NSJSONSerialization.JSONObjectWithData(myData, options: [])
if let promtions = promoJson as? [[String: AnyObject]] {
for promtion in promtions {
if let picture = promtion["picture"] as? String {
myPicture.append(picture)
}
if let path = promtion["path"] as? String {
myPath.append(path)
}
if let label = promtion["label"] as? String {
mylabel.append(label)
}
}
}
} catch let error as NSError {
print(error.debugDescription)
}
Alternative
Now that the issue is resolved, let me suggest you another way: instead of separate arrays for your data, use one array of objects holding your data.
For example, make a struct like this:
struct Promotion {
let picture: String
let path: String
let label: String
}
And an array for instances of this struct:
var myPromotions = [Promotion]()
Now we can decode the JSON, create objects from it then store them in the array:
do {
let promoJson = try NSJSONSerialization.JSONObjectWithData(myData, options: [])
if let promtions = promoJson as? [[String: AnyObject]] {
for promtion in promtions {
if let picture = promtion["picture"] as? String,
path = promtion["path"] as? String,
label = promtion["label"] as? String {
let promo = Promotion(picture: picture, path: path, label: label)
myPromotions.append(promo)
}
}
}
} catch let error as NSError {
print(error.debugDescription)
}
Now look at the content of the array, very convenient:
for promo in myPromotions {
print(promo.label)
print(promo.path)
print(promo.picture)
}
When you are converting it is already an array.
import Foundation
import UIKit
var myPicture = [String]()
var myPath = [String]()
var mylabel = [String]()
let jsonString = "[{\"picture\" : \"Picture 1 \", \"path\": \"Path 1\" , \"label\" : \"Label 1\"}]"
//Convert jsonString to NSData
let myData = jsonString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
do{
let promoJson = try NSJSONSerialization.JSONObjectWithData(myData, options:.AllowFragments) as! NSArray
for promtions in promoJson {
if let picture = promtions["picture"] as? String
{
myPicture.append(picture)
if let path = promtions["path"] as? String
{
myPath.append(path)
if let label = promtions["label"] as? String
{
mylabel.append(label)
}
}
}
}
}catch
{
print("Error with Json: \(error)")
}
print(myPicture.first) // "Optional("Picture 1 ")\n"
print(myPath.first) // "Optional("Path 1")\n"
print(mylabel.first) // "Optional("Label 1")\n"
This does the job.
In my mainviewcontroller's viewDidLoad() method I am firing few processes.
let api = JsonData() // create instance of JsonData class
api.loadJson(nil) // this method receives json and writes it in the file.
//Function to find file location
func getFileURL(fileName: String) -> NSURL {
let manager = NSFileManager.defaultManager()
let dirURL = manager.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false, error: nil)
return dirURL!.URLByAppendingPathComponent(fileName)
}
//file with this name was created in loadJson method
let filePath = getFileURL("JSONFromServer.txt").path!
//trying to read this file
let newDictionary = NSKeyedUnarchiver.unarchiveObjectWithFile(filePath) as! [Dictionary <String,AnyObject> ]
I was expecting that file will be created in api.loadJson and straight after it I will be able to read it. But for some reason when I use debugger I see that there is no file yet. And only when program goes out from viewdidload method I can see that file was created.
I wonder if program flow is specific?
Here is my JsonData class:
import Foundation
class JsonData {
var bankDict = [Dictionary <String,AnyObject> ]()
var arrayOfBanks: [[String:AnyObject]] = []
func loadJson(completion: ((AnyObject) -> Void)!) {
var urlString = "http://almaz.com/getjson.php"
let session = NSURLSession.sharedSession()
let sourceUrl = NSURL(string: urlString)
var task = session.dataTaskWithURL(sourceUrl!){
(data, response, error) -> Void in
if error != nil {
println(error.localizedDescription)
} else {
var error: NSError?
var jsonData = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &error) as! NSArray
//println(jsonData)
//convert from JSON into array of dictionaries
var rates = [ExchangeRates]() //instance of class Rate
var bnkDct = ["bank": "", "currency": "","buyrate": "", "sellrate": ""] //template
var indx : Int = 0 //index for iteration
for rate in jsonData{
let rate = ExchangeRates(rate as! NSDictionary)
rates.append(rate)
bnkDct["bank"] = rates[indx].bank
bnkDct["buyrate"] = rates[indx].buyRate
bnkDct["sellrate"] = rates[indx].sellRate
bnkDct["currency"] = rates[indx].currency
self.bankDict.append(bnkDct)
indx += 1
}
//println(self.bankDict)
//Store data in file
//File path and name
if let dirs : [String] = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true) as? [String] {
let dir = dirs[0] //documents directory
let filePath = dir.stringByAppendingPathComponent("JSONFromServer.txt");
NSKeyedArchiver.archiveRootObject(self.bankDict, toFile: filePath)
// println(filePath)
}
}
}
task.resume()
}
}
Your loadJson function takes a completion handler as a parameter but your loadJson function doesn't call it when it is done. Fix that first.
Then in your viewDidLoad function, pass in a completion handler when you call loadJson. The completion code you provide is where you should read and process the file saved by loadJson.
I've been trying to read this complex JSON Data in Swift, which i can read the "feed" and then "entry" until reaching "url" for each element in the JSON.
This is the JSON (Dictionary - Array - Dictionary - Array - Dictionary ):
{
"feed": {
"entry": [
{
"media$group": {
"media$content": [
{
"url": "http://..../photo.png"
}
]
}
}
]
}
}
This is my Photo Class where i define the things i need to get from JSON:
class Photo {
let TAG_FEED:String = "feed"
let TAG_ENTRY:String = "entry"
let TAG_MEDIA_GROUP:String = "media$group"
let TAG_MEDIA_CONTENT:String = "media$content"
let TAG_IMG_URL:String = "url"
}
This is my UIViewController where I'm trying to read the JSON :
func parseJsonData(data: NSData) -> [Photo] {
var photos = [Photo]()
var error:NSError?
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &error) as? NSDictionary
if error != nil {
println(error?.localizedDescription)
}
// how is it possible to read it here
return photos
}
After reading the array is it possible to store it array of Strings.
If you want to parse then use below piece of code and learn.
if let myFeed = jsonResult[TAG_FEED] as? Dictionary<String, AnyObject> {
if let myEntries = myFeed[TAG_ENTRY] as? Array<AnyObject> {
for myEntry in myEntries {
if let myMedia = myEntry[TAG_MEDIA_GROUP] as? Dictionary<String, AnyObject> {
if let contents = myMedia[TAG_MEDIA_CONTENT] as? Array<AnyObject> {
for myContent in contents {
if let url = myContent[TAG_IMG_URL] as? String {
// populate your model class here...
}
}
}
}
}
}
}
Change your jsonResult line to let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableLeaves, error: &error) as! Dictionary<String, AnyObject>!
As alternative you can use SwiftyJSON