why I cannot read data from plist? - ios

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

Related

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

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.

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

how to use dict inside a plist

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

How to filter plist arrays with boolean key value in swift

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?

persist dictionary to file and read it back

I am learning Swift. I have created an dictionary:
var myDict = Dictionary<String, String>()
myDict["AAA"] = "aaa"
myDict["BBB"] = "bbb"
Now I want to persist this dictionary to a file. I get a file path under documents:
let docDir = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).last as? String
let filePath = docDir.stringByAppendingPathComponent("MyFile.txt")
Until here, I don't know how to store myDict to the file. And also how to read the myDict back from file. Could someone please guide me through please?
You can use NSMutableDictionary
private var myDict: NSMutableDictionary!
For writing to user defaults:
let def:NSUserDefaults = NSUserDefaults.standardUserDefaults();
def.setObject(myDict, forKey: "YOUR_KEY");
def.synchronize();
For writing to file:
var text:String = ""
for (key, value) in myDict {
text += "\(key as! String)=\(value as! String)\n"
}
do {
try text.writeToFile(path, atomically: false, encoding: NSUTF8StringEncoding)
}
catch {/* error handling here */}
For reading:
let def:NSUserDefaults = NSUserDefaults.standardUserDefaults();
let ur:NSDictionary? = def.objectForKey("YOUR_KEY") as? NSDictionary;
if(ur == nil) {
myDict = NSMutableDictionary();
myDict.setValue("aaa", forKey:"AAA");
myDict.setValue("bbb", forKey:"BBB");
}
else{
myDict = NSMutableDictionary(dictionary: ur!)
}

Resources