how to get last element (array) in dictionary [string:Any] - ios

i have a dictionary plist and i have to get an array from that dictionary which is in the last. i have to get that array in my table
var dict = [String: Any]()
func readAndWriteData(){
if let path = Bundle.main.path(forResource: "Property List", ofType: "plist") {
var dictionary : NSDictionary?
if var array = NSArray(contentsOfFile: path)?.firstObject as? [String:Any] {
// array["hello"] = "hello"
// i have get these value by using key of each values
print(array)
tableView.reloadData()
}else{
dictionary = NSDictionary(contentsOfFile: path)
dict = dictionary as! [String:Any]
print(dict["featureImageArray"])
}
}
}

First of all you are using pretty objective-c-ish API to get and parse the property list. Don't do that, use Swift native types and there is a dedicated class to (de)serialize property lists.
And there is no last item in the dictionary. You get the array by key featureImageArray
var array = [[String:Any]]()
func readAndWriteData(){
let url = Bundle.main.url(forResource: "Property List", withExtension: "plist")!
do {
let data = try Data(contentsOf: url)
let propertyList = try PropertyListSerialization.propertyList(from: data, format: nil) as! [String:Any]
array = propertyList["featureImageArray"] as! [[String:Any]]
tableView.reloadData()
} catch {
print(error)
}
}
A still better way is to use custom structs and PropertyListDecoder.

Related

Swift JSON parsing and printing a specified value from an array

Hi I'm trying to get data from a certain JSON API. I can gat a snapshot of all values from the API, which is shown below. But I can't manage to put a specifiek row in a variable. This is the JSON form which I get. I want to print the "Description" value.Can someone help me with this?
And Hier is my code:
func apiRequest() {
let config = URLSessionConfiguration.default
let username = "F44C3FC2-91AF-5FB2-8B3F-70397C0D447D"
let password = "G23#rE9t1#"
let loginString = String(format: "%#:%#", username, password)
let userPasswordData = loginString.data(using: String.Encoding.utf8)
let base64EncodedCredential = userPasswordData?.base64EncodedString()
let authString = "Basic " + (base64EncodedCredential)!
print(authString)
config.httpAdditionalHeaders = ["Authorization" : authString]
let session = URLSession(configuration: config)
var running = false
let url = NSURL(string: "https://start.jamespro.nl/v4/api/json/projects/?limit=10")
let task = session.dataTask(with: url! as URL) {
( data, response, error) in
if let taskHeader = response as? HTTPURLResponse {
print(taskHeader.statusCode)
}
if error != nil {
print("There is an error!!!")
print(error)
} else {
if let content = data {
do {
let array = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
print(array)
if let items = array["items"] {
if let description = items["Description"] as? [[String:Any]]{
print(description as Any)
}
}
}
catch {
print("Error: Could not get any data")
}
}
}
running = false
}
running = true
task.resume()
while running {
print("waiting...")
sleep(1)
}
}
First of all the array is not an array and not AnyObject, it's a dictionary which is [String:Any] in Swift 3.
let dictionary = try JSONSerialization.jsonObject(with: content) as! [String:Any]
print(dictionary)
I don't know why all tutorials suggest .mutableContainers as option. That might be useful in Objective-C but is completely meaningless in Swift. Omit the parameter.
The object for key itemsis an array of dictionaries (again, the unspecified JSON type in Swift 3 is Any). Use a repeat loop to get all description values and you have to downcast all values of a dictionary from Any to the expected type.
if let items = dictionary["items"] as? [[String:Any]] {
for item in items {
if let description = item["Description"] as? String {
print(description)
}
}
}
Looks like items is an array that needs to be looped through. Here is some sample code, but I want to warn you that this code is not tested for your data.
if let items = array["items"] as? [[String: AnyObject]] {
for item in items {
if let description = item["Description"] as? String{
print("Description: \(description)")
}
}
}
This code above, or some variation of it, should get you on the right track.
use the SwiftyJSON and it would be as easy as json["items"][i].arrayValue as return and array with items Values or json["items"][i]["description"].stringValue to get a string from a row

parsing json data in for loop statement using swift 2

I am developing a app using swift2 am parsing JSON data to a UITableView which works perfectly when click on the cell it moves to other view controller and fetching some data to label box. The problem is when I clicks any cells on the table view it fetching same data to a view controller I dont know how to parse the data into for loop statement.
Json data(data am recieving from the server):
{
item: [
{
name: "name1",
id: "1",
},
{
name: "name2",
id: "2"
}
]
}
Code what I have tried:
created outlet labelname and labelid
var arrDict :NSMutableArray=[]
let urlstring = "www.anything.com"
let url = NSURL(string: urlString)
let data = try? NSData(contentsOfURL: url, options: [])
let json = JSON(data: data)
print(json)
//it helps to print all the json data in console
Now help me work with forloop statement
Try this,it helps you:-
for (_, subjson): (String, JSON) in json["item"]{
print("YOUR SUBJSON VALUE>> \(subjson["name"].stringValue)")
}
var listArray = Dictionary<String, AnyObject>()
listArray["name"] = json["item"]?.valueForKey("name") as! Array
listArray["id"] = json["item"]?.valueForKey("id") as! Array
var name = [""]
var id = [""]
name = listArray["name"] as! Array
id = listArray["id"] as! Array
for i in 0..<name.count{
print(name[i])
print(id[i])
}
hope it will help
Try this way
let array = json["item"] as! [NSDictionary]
for dict in array {
let name = dict["name"] as! String
let id = dict["id"] as! String
}
i hope this will help you
take all json data in an NSArray(if data is in Array)
like this:
let arr = json as! NSArray
for i in 0...arr.count-1
{
let items = arr[i] as! NSMutableDictionary
var abc = items.valueForKey("name"))as! String
//Like this you can take all array values
}
hope it will help you.

How to read from a plist with Swift 3 iOS app

-Disclaimer-
I'm extremely new to iOS and Swift development, but I'm not particularly new to programming.
I have a basic iOS application with Swift3 elements in it.I've created a plist file with some entries I want to read and display in my application. (No write access is necessary)
How can you read a value for a given key for a bundled plist file, in Swift3?
This seems like a really simple question to me, but a bunch of searching is making me question my whole conceptual approach.
Helpful tips would be appreciated.
Same way you have done in Swift 2.3 or lower just syntax is changed.
if let path = Bundle.main.path(forResource: "fileName", ofType: "plist") {
//If your plist contain root as Array
if let array = NSArray(contentsOfFile: path) as? [[String: Any]] {
}
////If your plist contain root as Dictionary
if let dic = NSDictionary(contentsOfFile: path) as? [String: Any] {
}
}
Note: In Swift it is better to use Swift's generic type Array and Dictionary instead of NSArray and NSDictionary.
Edit: Instead of NSArray(contentsOfFile: path) and NSDictionary(contentsOfFile:) we can also use PropertyListSerialization.propertyList(from:) to read data from plist file.
if let fileUrl = Bundle.main.url(forResource: "fileName", withExtension: "plist"),
let data = try? Data(contentsOf: fileUrl) {
if let result = try? PropertyListSerialization.propertyList(from: data, options: [], format: nil) as? [[String: Any]] { // [String: Any] which ever it is
print(result)
}
}
As Swift 4 introduces Codable
Step 1: Load the Plist File from bundle.
Step 2: Use PropertyListDecoder for the decoding of property list values into semantic Decodable types.
Step 3: Create Codable Struct
Complete code -
func setData() {
// location of plist file
if let settingsURL = Bundle.main.path(forResource: "JsonPlist", ofType: "plist") {
do {
var settings: MySettings?
let data = try Data(contentsOf: URL(fileURLWithPath: settingsURL))
let decoder = PropertyListDecoder()
settings = try decoder.decode(MySettings.self, from: data)
print("toolString is \(settings?.toolString ?? "")")
print("DeviceDictionary is \(settings?.deviceDictionary?.phone ?? "")")
print("RootPartArray is \(settings?.RootPartArray ?? [""])")
} catch {
print(error)
}
}
}
}
struct MySettings: Codable {
var toolString: String?
var deviceDictionary: DeviceDictionary?
var RootPartArray: [String]?
private enum CodingKeys: String, CodingKey {
case toolString = "ToolString"
case deviceDictionary = "DeviceDictionary"
case RootPartArray
}
struct DeviceDictionary: Codable {
var phone: String?
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
phone = try values.decodeIfPresent(String.self, forKey: .phone)
}
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
toolString = try values.decodeIfPresent(String.self, forKey: .toolString)
deviceDictionary = try values.decodeIfPresent(DeviceDictionary.self, forKey: .deviceDictionary)
RootPartArray = try values.decodeIfPresent([String].self, forKey: .RootPartArray)
}
}
Sample Plist file -> https://gist.github.com/janeshsutharios/4b0fb0e3edeff961d3e1f2829eb518db
Here is example how to get BundleID from Info plist:
var appBundleID = "Unknown Bundle ID"
if let bundleDict = Bundle.main.infoDictionary,
let bundleID = bundleDict[kCFBundleIdentifierKey as String] as? String {
appBundleID = bundleID
}
The same way you may easily access any key. This approach is good for many-target projects.
Here is a Swift 3 implementation, based on Nirav D's answer:
/// Read Plist File.
///
/// - Parameter fileURL: file URL.
/// - Returns: return plist content.
func ReadPlist(_ fileURL: URL) -> [String: Any]? {
guard fileURL.pathExtension == FileExtension.plist, let data = try? Data(contentsOf: fileURL) else {
return nil
}
guard let result = try? PropertyListSerialization.propertyList(from: data, options: [], format: nil) as? [String: Any] else {
return nil
}
print(result)
return result
}
For Swift 3.0, Following code directly targeting to key. Where as dict object will give everything which will be there in your plist file.
if let path = Bundle.main.path(forResource: "YourPlistFile", ofType: "plist"), let dict = NSDictionary(contentsOfFile: path) as? [String: AnyObject] {
let value = dict["KeyInYourPlistFile"] as! String
}
In AppDelegate File
var bundlePath:String!
var documentPath:String!
var plistDocumentPath:URL!
let fileManager = FileManager()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
{
bundlePath = Bundle.main.path(forResource: "Team", ofType: "plist")
documentPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
plistDocumentPath = URL.init(string: documentPath)?.appendingPathComponent("Team.plist")
print(plistDocumentPath.path)
if !fileManager.fileExists(atPath: plistDocumentPath.path){
do {
try fileManager.copyItem(atPath: bundlePath, toPath: plistDocumentPath.path)
} catch {
print("error Occured \(error.localizedDescription)")
}
}
return true
}
In ViewController
#IBOutlet weak var TeamTable: UITableView!
var appDelegate:AppDelegate!
var arrayForContacts:[[String:Any]]! // array object
override func viewDidLoad() {
super.viewDidLoad()
appDelegate = UIApplication.shared.delegate as! AppDelegate
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if appDelegate.fileManager.fileExists(atPath: appDelegate.plistDocumentPath.path){
arrayForContacts = []
if let contentOfPlist = NSArray.init(contentsOfFile: appDelegate.plistDocumentPath.path ){
arrayForContacts = contentOfPlist as! [[String:Any]]
TeamTable.reloadData()
}
}
}
You can also read value directly from your plist file by simply
let value = Bundle.init(for: AppDelegate.self).infoDictionary?["your plist key name"] as? Any

How to access a property list

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 = ""
}

why I cannot read data from plist?

This is part my code. But myDict is nil. The filename is right.I already checked for many times.
var myDict: NSDictionary?
if let path = NSBundle.mainBundle().pathForResource("CatData", ofType: "plist") {
myDict = NSDictionary(contentsOfFile: path)
}
if let dict = myDict {
print("print something")
}
your plist is array of dictionary so try
var myArray: NSArray?
if let path = NSBundle.mainBundle().pathForResource("Categories", ofType: "plist") {
myArray = NSArray(contentsOfFile: path)
}
if let array = myArray {
for item: AnyObject in array {
if let item = item as? NSDictionary {
if let categoryTitle = item["CategoryTitle"] as? NSString {
print("categoryTitle = ", categoryTitle)
}
if let imageNames = item["ImageNames"] as? NSArray {
print("imageNames = ", imageNames)
}
}
}
}
Providing your file name is correct, and your plist has been added to the bundle:
You need to make sure your file is the type you're expecting.
For example. The root of your plist is an Array, and you're looking to get a Dictionary out of it.
So lets rewrite your code:
var myArray: Array? {
if let path = NSBundle.mainBundle().pathForResource("CatData", ofType: "plist") {
myArray = NSArray(contentsOfFile: path) as! [[String:AnyObject]]
}
if let array = myArray {
print("print something")
}
}

Resources