I have a plist file like
<dict>
<key>horse</key>
<dict>
<key>level</key>
<integer>2</integer>
</dict>
</dict>
and I load it by code bellow
let path = NSBundle.mainBundle().pathForResource("test", ofType: "plist")
dataBase = NSDictionary(contentsOfFile: path!)
let array = NSMutableArray()
for member in (dataBase.allKeys) {
let level = member.valueForKey("level") as! Int
if () {
//do something
}
}
when the app runs, it will crash. The reason I think is that member in the dataBase can't be cast to NSDictionary since it's NSTaggedPointerString, I don't know how to make it work.
update:
The previous question, I have addressed the answer by #Wonzigii, and now I got the right dict using this method I defined validateCard(), which is #Wonzigii said bellow.
func validateCard() -> NSArray?
Now I want to randomly retrieve its item inside the new array to use it to do something, what I'm solving this issue is using a random index, but seem I can't get the array item by index, since if I did so, I can't use it to get the next layer dict. what should I do next?
if let avaliableCardDeck = self.validateCard() {
for _ in 0...16 {
let maxAvaliableCards = avaliableCardDeck.count
let index = Int(arc4random()) % maxAvaliableCards
let cardInfo = avaliableCardDeck[index]
let newCard = PlayCard()
newCard.rank = cardInfo.valueForKey("number") as! Int
newCard.imageName = cardInfo.valueForKey("imageSource") as? String
addCard(newCard)
}
}
The reason is allKeys will return an array contains type AnyObject.
So yet member, in this case, is AnyObject type.
for member in (dataBase!.allKeys) where member as? String == "horse" {
let integer = dataBase?.valueForKeyPath("horse.level") as! Int
print(integer)
}
Note that allKeys always return top level keys.
Edit:
The below code will use member as the key to loop through the dictionary to retrieve deeper value.
for member in (dataBase!.allKeys) {
if let dic = dataBase?.valueForKey(member as! String) {
// get the level value or something else
let integer = dic.valueForKey("level") as! Int
print(integer)
}
}
More Swiftly way(without forced unwrapping, aka, !):
if let path = NSBundle.mainBundle().pathForResource("test", ofType: "plist"), db = NSDictionary(contentsOfFile: path) as? [String: AnyObject] {
for member in db.keys {
if let dic = db[member] {
// get the level value or something else
let integer = dic.valueForKey("level") as! Int
print(integer)
}
}
}
Try this out. If the path and all are correct this code must work, or else it will not execute. Will surely not crash
guard let path = NSBundle.mainBundle().pathForResource("test", ofType: "plist") else {
return
}
if let dataBase = NSDictionary(contentsOfFile: path), member = dataBase["horse"] as? [String: AnyObject] {
if let level = member["level"] as? Int {
//do something
}
}
Edit: Giving a generic one
guard let path = NSBundle.mainBundle().pathForResource("test", ofType: "plist") else {
return
}
if let dataBase = NSDictionary(contentsOfFile: path) {
for (_, value) in dataBase {
if value is [String: AnyObject], let level = value["level"] as? Int {
//do something
}
}
}
Related
I'm parsing a property list that includes and array of numbers. I then cast those numbers as an array of TimeIntervals. The array included in the .plist file reads:
[9.2,13.1,14.2,18,19.2,27.6,28.1,32.1]
The gist of the class:
class moveableElementNode: SKSpriteNode, EventListener {
fileprivate var times = [TimeInterval]()
func didMoveToScene() {
unpackData()
print(times)
}
func unpackData() {
if let path = Bundle.main.path(forResource: "Data", ofType: "plist") {
if let dictionary = NSDictionary(contentsOfFile: path) {
if (dictionary.object(forKey: "Data") != nil) {
if let dataDict:[String : Any] = dictionary.object(forKey: "Data") as? [String : Any] {
for (key, value) in dataDict {
if key == "times" {
times = value as! [TimeInterval]
}
}
}
}
}
}
}
}
For some reason when ! print the array to the console I get: [9.1999999999999993, 13.1, 14.199999999999999, 18.0, 19.199999999999999, 27.600000000000001, 28.100000000000001, 32.100000000000001]
Can anyone tell me whats going on?? Why have these single decimal place numbers been distorted?
I try to compile on device but i get this error. Any help?. In the simulator works perfectly.
I get an ambiguous use of subscript error in the following code and was hoping somebody else has encountered this and know the fix.
case .Success:
if response.response?.statusCode == 200 {
print ("Respuesta 200")
if let value = response.result.value {
let respuestaJSON = JSON(value)
let objsonUSUARIOS = respuestaJSON["d"].object
let arrayUsuarios = objsonUSUARIOS["results"]!
//print ("Usuarios: ",String(arrayUsuarios))
for i in 0 ..< arrayUsuarios!.count{
let boletines = boletinJSON()
if let item = arrayUsuarios![i] as? [String: AnyObject]{
)
if let person = item["Title"] as? String
{
boletines.name = person
}
if let person = item["Portada"] as? String
{
boletines.imagen = person
}
if let person = item["Created"] as? String
{
boletines.fecha = person
}
if let person = item["AttachmentFiles"] as? [String: AnyObject] {
if let itemAttach = person["__deferred"] as? [String: AnyObject]{
if let itemdeferred = itemAttach["uri"] as? String {
boletines.urldescarga = itemdeferred
}
}
}
self.boletin.append(boletines)
self.view.hideToastActivity()
}
}
}
self.tableView.reloadData()
// self.view.hideToastActivity()
}
Inform the compiler what the intermediary object objsonUSUARIOS is of type
let objsonUSUARIOS = respuestaJSON["d"].object
After the above statement, the compiler does not know what kind of object he is dealing with. So make sure that you can actually do all the casting as below
let objsonUSUARIOS = respuestaJSON["d"].object as! Dictionary
let arrayUsuarios = objsonUSUARIOS["results"]! as! Array
The problem is that you have not specified the type of object arrayUsuarios is Array, so try to explicit type cast the arrayUsuarios Array
let arrayUsuarios = objsonUSUARIOS["results"] as! [[String: AnyObject]]
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 = ""
}
I am using this code to filter for certain strings in my plist array:
func SearchC(){
let pathMC = NSBundle.mainBundle().pathForResource("myPlistArray", ofType: "plist")
let dictMC = NSDictionary(contentsOfFile: pathMC!)
myPlistArray = dictMC!["Questions"]!.mutableCopy() as? Array
if let questionArray = myPlistArray as? [[String:AnyObject]] {
let answersC = questionArray.filter({
if let correct = $0["CorrectAnswer"] as? String {
return correct.uppercaseString == "C"
}
return false
})
print("\(answersC)")
}
}
I now need to filter for items which have the boolean value of “YES”, or “NO”. I tweaked the code above and came up with the following:
func SearchYES(){
let pathMC = NSBundle.mainBundle().pathForResource("myPlistArray", ofType: "plist")
let dictMC = NSDictionary(contentsOfFile: pathMC!)
myPlistArray = dictMC!["Questions"]!.mutableCopy() as? Array
if let questionArray = myPlistArray as? [[String:AnyObject]] {
let isFavorite = questionArray.filter({
if let favorite = $0["isFavorite"] as? String {
return favorite.uppercaseString == "YES"
}
return false
})
print("\(isFavorite)")
}
}
BUT it’s not working. Does anyone know how to filter items which have a boolean key value of TRUE/YES?
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")
}
}