Swift 2.0 : Json Array Parsing errors - arrays

in Swift 1.2
https://gist.github.com/anonymous/a167148a8a6d169292ff
in Swift 2.0 (error)
, so I change my code as follows.
let url = NSURL(string:"http://dl-8.one2up.com/onetwo/content/2015/6/15/9c3b51249fbbe20ca9d841401e276d97.php")
let allContactsData = NSData(contentsOfURL:url!)
do{
var allContacts : AnyObject! = try NSJSONSerialization.JSONObjectWithData(allContactsData!, options: NSJSONReadingOptions())
}catch{
print(error)
}
if let json = allContacts as? Array<AnyObject> {
print(json)
for index in 0...json.count-1 {
let contact : AnyObject? = json[index]
let collection = contact! as! Dictionary<String, AnyObject>
let name : AnyObject? = collection["AnimeName"]
let cont : AnyObject? = collection["Episodes"]
names.append(name as! String)
episodes.append(cont as! String)
}
}
print(names)
print(episodes)
But that doesn't work.
if let json = allContacts as? Array< AnyObject >
error : Use of unresolved identifier 'allContacts'

Your allContacts variable is created in the do block, therefore its scope is limited to the do block, and cannot be accessed outside of that block. If you want it to be accessible outside the block, declare it outside of the block, but then continue to assign it inside the block. IE:
let allContactsData = NSData(contentsOfURL:url!)
var allContacts:AnyObject
do{
allContacts = try NSJSONSerialization.JSONObjectWithData(allContactsData!, options: NSJSONReadingOptions())
}catch{
print(error)
}

do{
var allContacts = try NSJSONSerialization.JSONObjectWithData(allContactsData!, options: NSJSONReadingOptions()) as! [Dictionary<String, AnyObject>]
for contact in allContacts {
let name : AnyObject? = contact["AnimeName"]
let cont : AnyObject? = contact["Episodes"]
names.append(name as! String)
episodes.append(cont as! String)
}
}catch{
print(error)
}

Related

Swift Array sort with JSON

Data:
tried get data from JSON
has code with Swift run on Playground
var roadWayStatusArray = [AnyObject]()
let url = URL(string: "http://od.moi.gov.tw/data/api/pbs")
let data = try? Data(contentsOf: url!)
let json = try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers)
if let results = json as? [String : AnyObject] {
if let result = results["result"] as? [[String : AnyObject]] {
for data in result {
let happendate = data["happendate"] as? String
roadWayStatusArray.append(data as AnyObject!)
}
}
}
I has tried using roadWayStatusArray.sort(by: >) but Xcode report me Ambiguous reference member '>'
How to create sort by hapendate or happentime
Your roadWayStatusArray is an array of AnyObject. There is no > operator defined for AnyObject.
The objects in roadWayStatusArray are actually dictionaries that look like this:
{
UID = "10602090007-0";
areaNm = "\U4e2d\U5c71\U9ad8\U901f\U516c\U8def-\U570b\U9053\Uff11\U865f";
comment = "\U5317\U4e0a.\U4e2d\U58e2\U670d\U52d9\U5340 \U51fa\U53e3\U531d\U9053\U4e2d \U53f3\U5074 \U5c0f\U5ba2\U8eca\U505c\U653e\Uff0c\U99d5\U99db\U7591\U4f3c\U7761\U8457\U4e86";
direction = "\U5317\U4e0a";
happendate = "2017-02-09";
happentime = "01:08:00.0000000";
modDttm = "2017-02-09 01:15:43.603";
region = N;
road = "";
roadtype = "\U5176\U4ed6";
srcdetail = "\U71b1\U5fc3\U807d\U773e";
x1 = "121.73558";
y1 = "25.12263";
}
You need to call sort(by:) with a closure that determines the sort order. For example, if you want to sort by happendate and then happentime:
roadWayStatusArray.sort(by: { (lhsAny, rhsAny) -> Bool in
let lhs = lhsAny as? [String: AnyObject]
let rhs = lhsAny as? [String: AnyObject]
let lhsKey = (lhs?["happendate"] as? String ?? "", lhs?["happentime"] as? String ?? "")
let rhsKey = (rhs?["happendate"] as? String ?? "", rhs?["happentime"] as? String ?? "")
return lhsKey < rhsKey
})

How to Save complex Arrayobjects to device using NSKeyedArchiver swift

I want to save an array of any class (e.g let array = SymptomsModel) type into device using NSKeyedArchiver in swift .
I Know how to save an array if SymptomsModel class contains all variables with primitive data types , but don't know how to save it if also contains an array of any other class as its property
Below I have explained my problem with the help of example , please go through it and provide solution.
I have a class
class SymptomsModel: NSObject, NSCoding ,ResponseJSONObjectSerializable {
var slug:String?
var name:String?
var images:[Sym_images]?
var videos:[Sym_videos]?
struct Keys {
static let Name = "name"
static let Slug = "slug"
static let Images = "images"
static let Videos = "videos"
}
required init(json:SwiftyJSON.JSON) {
self.slug = json["slug"].string
self.name = json["name"].string
self.images = [Sym_images]()
if let imagesJSON = json["images"].array {
for(imagesJSON) in imagesJSON {
if let newImages = Sym_images(json: imagesJSON){
self.images?.append(newImages)
}
}
}
self.videos = [Sym_videos]()
if let videosJSONArray = json["videos"].array {
for(videosJSON) in videosJSONArray {
if let newVideos = Sym_videos(json: videosJSON){
self.videos?.append(newVideos)
}
}
}
}
init(dictionary: [String : AnyObject]) {
self.name = dictionary[Keys.Name] as? String
self.slug = dictionary[Keys.Slug] as? String
self.images = dictionary[Keys.Images] as? [Sym_acc_images_objects]
self.videos = dictionary[Keys.Videos] as? [Sym_acc_videos_objects]
}
func encodeWithCoder(archiver: NSCoder) {
archiver.encodeObject(name, forKey: Keys.Name)
archiver.encodeObject(slug, forKey: Keys.Slug)
archiver.encodeObject(images, forKey: Keys.Images)
archiver.encodeObject(videos, forKey: Keys.Videos)
}
required init(coder unarchiver: NSCoder) {
super.init()
name = unarchiver.decodeObjectForKey(Keys.Name) as? String
slug = unarchiver.decodeObjectForKey(Keys.Slug) as? String
self.images = unarchiver.decodeObjectForKey(Keys.Slug) as? [Sym_acc_images_objects]
self.videos = unarchiver.decodeObjectForKey(Keys.Slug) as? [Sym_acc_videos_objects]
}
and a PersistanceManager class to save the data with NskeyedArchiver as
class PersistenceManager {
class private func documentsDirectory() -> NSString {
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let documentDirectory = paths[0] as String
return documentDirectory
}
class func saveNSArray(arrayToSave: NSArray, key: String) {
print(" saveNSArray key : \(key)")
let file = documentsDirectory().stringByAppendingPathComponent(key)
NSKeyedArchiver.archiveRootObject(arrayToSave, toFile: file)
}
class func loadNSArray(path: String) -> NSArray? {
print(" loadNSArray key : \(path)")
let file = documentsDirectory().stringByAppendingPathComponent(path)
let result = NSKeyedUnarchiver.unarchiveObjectWithFile(file)
return result as? NSArray
}
}
And Here is my implimentation of saving and then retreiving the array
class ViewController: UIViewController{
var ArraySymptom = [SymptomsModel]()
override func viewDidLoad() {
super.viewDidLoad()
ArraySymptom = loadArray()
//saving data in device
PersistenceManager.saveNSArray(ArraySymptom, key: "Symptom")
//loading data from device
if let value = PersistenceManager.loadNSArray("Symptom") as? [SymptomsModel] {
let images = value[0].images
print("images : \(images)")
let slug = value[0].slug
print("slug : \(slug)")
}
}
Here am able to get the value of slug but not able to fetch images value.
It might be happening because slug is of String type and Images is of Custom Class type .
Please suggest me the way i can get it done .
Is is possible to save these type of arrays with NSKeyedArchiver , so that i can access images value just by retreiving ArraySymptom from device.
Silly mistake it was
I was getting nil in Images because it was decoded with wrong key , it was copy paste mistake
The Error was in this function..
required init(coder unarchiver: NSCoder) {
super.init()
name = unarchiver.decodeObjectForKey(Keys.Name) as? String
slug = unarchiver.decodeObjectForKey(Keys.Slug) as? String
self.images = unarchiver.decodeObjectForKey(Keys.Slug) as? [Sym_images]
self.videos = unarchiver.decodeObjectForKey(Keys.Slug) as? [Sym_videos]
}
And the correct decoding must be
self.images = unarchiver.decodeObjectForKey(Keys.Images) as?
[Sym_images]
self.videos = unarchiver.decodeObjectForKey(Keys.Videos) as?
[Sym_videos]

Swift - read plist file to an array?

I have created a mini translation from English words to Spanish words. I would like to use the englishArray.plist instead of my englishArray = ["the cat"] How can I create this?
I have also used a localizable.strings to retrieve the value "the cat" for "el gato" but I would like to retrieve this from englishArray.plist
I started off with this but not sure if I'm on the right path
let path = NSBundle.mainBundle().pathForResource("englishArray", ofType: "plist")
let plistEnglishArray = NSArray(contentsOfFile: path!)
Here is the rest of my code:
var englishArray: [String] = ["rainbow", "boots", "heart", "leaf", "umbrella", "tired", "angry", "cry", "the cat" ]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.translateTextField.delegate = self
picker.delegate = self
picker.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func translateButtonTapped(sender: UIButton) {
let emptyString = self.translateTextField.text
if (emptyString!.isEmpty) {
print("please enter a word")
}
for transIndex in englishArray.indices {
if englishArray[transIndex] == emptyString!.lowercaseString {
//englishArray
//translateLabel.text = "\(spanishArray[transIndex])"
translateLabel.text = NSLocalizedString(emptyString!.lowercaseString, comment:"")
print(emptyString)
return
}
}
}
Swift 4
The absolute simplest way to do this is
let url = Bundle.main.url(forResource: "Sounds", withExtension: "plist")!
let soundsData = try! Data(contentsOf: url)
let myPlist = try! PropertyListSerialization.propertyList(from: soundsData, options: [], format: nil)
The object myPlist is an Array or Dictionary, whichever you used as the base of your plist.
Change your root object to Array, then
var myEnglishArray: [String] = []
if let URL = NSBundle.mainBundle().URLForResource("englishArray", withExtension: "plist") {
if let englishFromPlist = NSArray(contentsOfURL: URL) as? [String] {
myEnglishArray = englishFromPlist
}
}
Swift 4
You can use Codable which is pure swift type.
Firstly load Plist file from bundle then use PropertyListDecoder
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("array is \(settings?.englishArray ?? [""])")//prints array is ["Good morning", "Good afternoon"]
} catch {
print(error)
}
}
}
}
struct MySettings: Codable {
var englishArray: [String]?
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
englishArray = try values.decodeIfPresent([String].self, forKey: .englishArray)
}
}
This will read a resource in your bundle with the name "englishArray.plist" and store it in the immutable variable english. It will be an Optional that you should test before using.
It uses a closure to read the file and return the array, this lets you use a immutable value rather than a mutable variable that can be changed. It's a good idea to use immutables wherever you can - they promote stability.
import Foundation
let english:[String]? = {
guard let URL = NSBundle
.mainBundle()
.URLForResource("englishArray", withExtension: "plist") else {
return nil
}
return NSArray(contentsOfURL: URL) as? [String]
}()
Here is the solution for swift 3. For this solution you do not need to change types in your plist structure (keep Dictionary, Array, as is). Also note that since your array's name in plist is also englishArray so the (value for key) argument in the second if statement is also englishArray.
var myEnglishArray: [String] = []
if let URL = Bundle.main.url(forResource: "englishArray", withExtension: "plist") {
guard let englishFromPlist = NSDictionary(contentsOf: URL) else { return [] }
if let englishArray = englishFromPlist.value(forKey: "englishArray") as? [String] {
for myEnglish in englishArray {
myEnglishArray.append(myEnglish)
}
}
}

Swift: Parsing Arrays out of JSONs

[{"name":"Air Elemental","toughness":"4","printings":["LEA","BTD","7ED","8ED","9ED","10E","DD2","M10","DPA","ME4","DD3_JVC"]}]
I have a JSON where there is an array in each listing called "printings" as seen below, how would I take this array out of each listing and convert it into a string like "LEA-BTD-7ED". Here is what I have so far but its crashing.
let err : NSErrorPointer?
let dataPath = NSBundle.mainBundle().pathForResource("cardata", ofType: "json")
let data : NSData = try! NSData(contentsOfFile: dataPath! as String, options: NSDataReadingOptions.DataReadingMapped)
do{
var contents = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments) as! [AnyObject]
for var i = 0;i<contents.count;++i{
let printing = contents[i]["printings"] as! String
}
}
Here's the code:
let path = dataPath!
if let JSONData = NSData(contentsOfFile: path)
{
do
{
if let dictionariesArray = try NSJSONSerialization.JSONObjectWithData(JSONData, options: NSJSONReadingOptions()) as?
[[String: AnyObject]]
{
for dictionary in dictionariesArray
{
if let printingsArray = dictionary["printings"] as? [String]
{
let printingsString = printingsArray.joinWithSeparator("-")
print(printingsString)
}
}
}
}
catch
{
print("Could not parse file at \(path)")
}
}
Executing it prints "LEA-BTD-7ED-8ED-9ED-10E-DD2-M10-DPA-ME4-DD3_JVC"
You can't cast an Array (contents[i]["printings"]) to a String. What you want is Array's joinWithSeparator() method, like this:
let printing = contents[i]["printing"] as! Array
let printingStr = printing.joinWithSeparator("-")
(Actually, I'm not sure whether you need the as! Array; try it without it.)

Swift NSUserDefaults setObject for Array

i need to save with NSUserDefaults an array that i get from jSON, the problem is it save only the first string and not all the array. So if the array is like NewYork,London,Rome .. it save only NewYork. I use it for a picker view.
This is the code:
EDIT
For save the Array from jSON:
if let jsonData = NSJSONSerialization.JSONObjectWithData(urlData!, options: nil, error: &error) as? [String:AnyObject] { // dictionary
if let locationsArray = jsonData["locations"] as? [[String:AnyObject]] { // array of dictionaries
for locationDictionary in locationsArray { // we loop in the array of dictionaries
if let location = locationDictionary["location_name"] as? String { // finally, access the dictionary like you were trying to do
// println(location)
var locationSave: Void = save.setObject(location, forKey: "Location")
}
}
}
}
}
and for request the Array:
var Location = save.objectForKey("Location")!
var pickerviewFields = Location
return pickerviewFields.count
Thanks in advance!
You can only save an NSArray, if the Array is a Swift Array, you will need to convert it. Also, NSArray and NSDictionary objects, their contents must be property list objects.
Here's how you would convert the Array:
var MyArray = ["a", "b", "c"]
var MyNSArray: NSArray
MyNSArray = MyArray as NSArray
println("\(MyNSArray)")
Prints: (a,b,c)
I have a small example with some sample JSON:
var myJSONString: NSString = "{ \"locations\" : [ { \"location_name\" : \"A\" }, { \"location_name\" : \"B\" }, { \"location_name\" : \"C\" }, { \"location_name\" : \"D\" } ] }"
var urlData: NSData? = NSData()
var error: NSError?
var save = NSUserDefaults.standardUserDefaults()
urlData = myJSONString.dataUsingEncoding(NSUTF8StringEncoding)
if let jsonData = NSJSONSerialization.JSONObjectWithData(urlData!, options: nil, error: &error) as? NSDictionary { // dictionary
if let locationsArray = jsonData["locations"] as? NSArray { // array of dictionaries
for locationDictionary in locationsArray { // we loop in the array of dictionaries
if let location = locationDictionary["location_name"] as? NSString {
println(location)
}
}
NSUserDefaults.standardUserDefaults().setObject(locationsArray, forKey: "locationArray")
}
}
println(save.dictionaryRepresentation())
You can try this:
Writing
let locationArray = ["London", "NewYork", "Rome"]
let locationData = NSKeyedArchiver.archivedDataWithRootObject(locationArray)
NSUserDefaults.standardUserDefaults().setObject(locationData, forKey: "Location")
NSUserDefaults.standardUserDefaults().synchronize()
Reading
let locationData = NSUserDefaults.standardUserDefaults().objectForKey("Location") as? NSData
if let locationData = locationData {
let locationArray = NSKeyedUnarchiver.unarchiveObjectWithData(locationData) as? [String]
if let locationArray = locationArray {
println(locationArray)
}
}

Resources