Lazy load plist dictionary element(s) - ios

The usual method for loading data from a dictionary contained in a plist is as below:
NSString *path = [[NSBundle mainBundle] pathForResource:#"Data" ofType:#"plist"];
NSDictionary *data= [NSDictionary dictionaryWithContentsOfFile:path];
Is there a way to import only the element(s) specified in a key / set of keys, like:
NSDictionary *data= [NSDictionary dictionaryWithContentsOfFile:path forKey:key];
The idea is to perform lazy loading of dictionary contents by key.

So based on my comment above, you could add a class method to the NSDictionary via a category. You could do something like (not tested BTW).
+ (NSDictionary *)dictionaryWithContentsOfFile:(NSString *)path forKeys:(NSArray *)keys
{
NSMutableDictionary *newDictionary = nil;
NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:path];
if (dictionary) {
newDictionary = [NSMutableDictionary dictionary];
for (id key in dictionary.allKeys) {
if ([keys containsObject:key]) {
newDictionary[key] = dictionary[key];
}
}
}
return [newDictionary copy];
}
If you did this, you'd see your spike in memory, but it should subside once dictionary is freed.
Alternatively, take a look at YAJL (https://github.com/lloyd/yajl). I've used this when dealing with very large JSON files. This was mainly the stream it in chunks. It is event driven, so you should be able to stream it in and detect the keys you want (hopefully).

please try the below method.
- (void)viewDidLoad
{
NSMutableArray *arry;
arry = [[NSMutableArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Catalog" ofType:#"plist"];
NSDictionary *dic = [menuArray objectAtIndex:indexPath.row];
lblName.text = [dic objectForKey:#"MenuName"];
}

Related

iOS - extracting data from a plist not working

This is a routine exercise. I have done it a number of times in my current project and it has worked fine. I copied the code line for line, same initializations. My plist data goes into a dictionary but then it does not go into its respective arrays in their initializations. I have a method called initArraysPlist
-(void)initArraysPlist{
NSString *path1 = [[NSBundle mainBundle] pathForResource:#"trainerProfile" ofType:#"plist"];
// Load the file content and read the data into arrays
NSDictionary *dict1 = [[NSDictionary alloc] initWithContentsOfFile:path1];
trainerNames = [dict1 objectForKey:#"Names"];
trainerIcons = [dict1 objectForKey:#"Icons"];
trainerFactSheet= [dict1 objectForKey:#"Fact Sheet"];
trainerFocus = [dict1 objectForKey:#"Focus"];
trainerContactInfo= [dict1 objectForKey:#"Contact Info"];
}
Ive done this a few times and it currently works in my code. all the values are correct. Ive checked it many times. when
Please read the comments for the each line.
NSString *path1 = [[NSBundle mainBundle] pathForResource:#"trainerProfile" ofType:#"plist"]; // **check if your plist is actually added in Bundle.If its there move to second line , if not then add plist in bundle.**
NSDictionary *dict1 = [[NSDictionary alloc] initWithContentsOfFile:path1];// **if plist is added in bundle , then check if you are getting value for dict1 . If no then you might be making some mistake in plist structure.**
For more clarifications please post your plist if possible.
Please try this code it may be helpful to you
// Read plist from bundle and get Root Dictionary out of it
NSDictionary *dictRoot = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"data" ofType:#"plist"]];
// Your dictionary contains an array of dictionary
// Now pull an Array out of it.
NSArray *arrayList = [NSArray arrayWithArray:[dictRoot objectForKey:#"catlist"]];
// Now a loop through Array to fetch single Item from catList which is Dictionary
[arrayList enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) {
// Fetch Single Item
// Here obj will return a dictionary
NSLog(#"Category name : %#",[obj valueForKey:#"category_name"]);
NSLog(#"Category id : %#",[obj valueForKey:#"cid"]);
}];

How do I get values from a tiered .plist?

I've already looked at Parse Plist (NSString) into NSDictionary and deemed it to be not a duplicate, as that question and its answer do not address my concerns.
I have a .plist file in the file system structured like this:
The source code of this .plist file looks like this:
{
"My App" = {
"Side Panel" = {
Items = {
Price = "#123ABC";
};
};
};
}
I know how to get an item in the Root like this:
[[NSBundle mainBundle] pathForResource:#"filename" ofType:#"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSString value = [dict objectForKey:#"key"]);
But what if the structure is like mine, with tiered dictionaries? How do I get the value of Price?
I would like to do this all in one method, ideally like this:
Calling
NSString *hexString = [self getColorForKey:#"My App.Side Panel.Items.Price"];
Definition
- (NSString *) getColorForKey: (NSString *)key
{
NSArray *path = [key componentsSeparatedByString:#"."];
NSDictionary *colors = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Colors" ofType:#"plist"]];
NSString *color = #"#FFFFFF"; // white is our backup
// What do I put here to get the color?
return color;
}
Here's the solution that worked for me:
+ (NSString*) getHexColorForKey:(NSString*)key
{
NSArray *path = [key componentsSeparatedByString:#"."];
NSDictionary *colors = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Colors" ofType:#"plist"]];
NSString *color = #"#FFFFFF";
for (NSString *location in path) {
NSObject *subdict = colors[location];
if ([subdict isKindOfClass:[NSString class]])
{
color = (NSString*)subdict;
break;
}
else if ([subdict isKindOfClass:[NSDictionary class]])
{
colors = (NSDictionary*)subdict; // if it's a dictinoary, our color may be inside it
}
else
{
[SilverLog level:SilverLogLevelError message:#"Unexpected type of dictinoary entry: %#", [subdict class]];
return color;
}
}
return color;
}
where key is an NSString that matches /^[^.]+(\.[^.]+)*$/, meaning it looks like my targeted #"My App.Side Panel.Items.Price".
Yes I understand what you're looking to accomplish; thank you for the clarification. I will however add that the resources and advice I have written do provide the necessary information resolve your problem.
That said, the following gets your dictionary:
NSURL *plistURL = [[NSBundle mainBundle] URLForResource:#"Info" withExtension:#"plist"];
NSData *plistData = [NSData dataWithContentsOfURL:plistURL];
NSDictionary *tieredPlistData = [NSPropertyListSerialization propertyListWithData:plistData
options:kCFPropertyListImmutable
format:NULL
error:nil];
Then, if we're interested in the information contained in Items
NSDictionary *allItemsDictionary = tieredPlistData[#"My App"][#"Side Panel"][#"Items"];
Assuming that Items will contain a number of objects, you could use
NSArray *keys = [allItems allKeys];
for(NSString *key in keys){
NSString *colorValue = allItemsDictionary[key];
// do something with said color value and key
}
Or, if there is a single value you need, then just reference that key
NSString *colorForPriceText = allItemsDictionary[#"Price"];
But a few tips:
It's generally considered a better idea to keep frequently accessed values in code instead of a plist/file that is loaded at runtime.
That said, you wouldn't put your call to load from NSBundle in the same method you would use to query a specific value. In your example, every time you need a color, you end up re-accessing NSBundle and pile on unneeded memory allocations. One method would load the plist into an iVar NSDictionary and then that NSDictionary would be used separately by another method.

how to load plist data into array in IOS property list

NSString *path = [[NSBundle mainBundle] pathForResource:#"recipes" ofType:#"plist"]];
NSDictionary *dict = [[NSDictionary alloc] initwithContentOfFile:path];
NSArray *textData=[NSArray new];
textData = [dict objectForkey:#"TableData"];
textData is my array name,
recipes is plist name
after excuting my text data is being empty...
where is the mistake.
The problem is that you converting .plist to dictionary in the wrong way. Check dict property, it should be nil. Code to create NSDictionary from .plist file is listed below:
CFPropertyListRef plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault,
(__bridge CFDataRef)propertyListData,
kCFPropertyListImmutable, NULL);
NSDictionary *settings = (__bridge NSDictionary *)plist;
Try this:
textData = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"recipes" ofType:#"plist"]];
Anyways, you may can take a look of this tutorial:
http://ios-blog.co.uk/tutorials/how-to-populate-a-uitableview-from-a-plist-property-list/

.plist Data can not be Loaded From NSArray to NSDictionary

I am fairly new to Objective-C.
I have created on .plist in which all data stored in Response Dictionary.
NSString *myListPath = [[NSBundle mainBundle] pathForResource:#"OffersList" ofType:#"plist"];
dic = [NSDictionary dictionaryWithContentsOfFile:myListPath];
tableData = [dic objectForKey:#"Response"];
Now i have converted that tabledata to Dictionary.
NSDictionary *dict = [tableData objectAtIndex:indexPath.row];
cell.titleLabel.text = [dict objectForKey:#"title"];
cell.nowLabel.text = [dict objectForKey:#"price"];
cell.saveLabel.text = [dict objectForKey:#"rondel"];
Now, Problem is that it only load's first 10 data.
I am also tried to print in log but after 10th data it's values seen as NULL.
Try to make a dump of the whole dic so that you can check exactly what data it contains:
NSLog(#"Content of tableData", [dic description]);
Then double check the log content for the tableData element with the .plist content.

iOS Dictionary causes memory leak

Why would the following implementation of the Dictionary cause a memory leak? See the screenshot below as well. Practically all of the leaks there are from this method.
- (void) setLocation:(NSString *) location:(NSString *) turnPage {
NSLog(#"Start setLocation");
//---get the path to the property list file---
NSString *localPlistFileNameConf = [[self documentsPath] stringByAppendingPathComponent:#"Config.plist"];
NSMutableDictionary *copyOfDict;
//---if the property list file can be found---
if ([[NSFileManager defaultManager] fileExistsAtPath:localPlistFileNameConf]) {
//---load the content of the property list file into a NSDictionary object---
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:localPlistFileNameConf];
//---make a mutable copy of the dictionary object---
copyOfDict = [dict mutableCopy];
[dict release];
}
else {
//---load the property list from the Resources folder---
NSString *pListPath = [[NSBundle mainBundle] pathForResource:#"Config" ofType:#"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:pListPath];
//---make a mutable copy of the dictionary object---
copyOfDict = [dict mutableCopy];
[dict release];
}
location = [self checkLocationValidity:location:turnPage];
[copyOfDict setValue:location forKey:#"Location"];
[self writeConfigToFile:copyOfDict];
NSLog(#"End setLocation");
}
You're not releasing copyOfDict anywhere. You own any object created with a method that starts with copy, so you need to release those objects. It's probably misreporting the source as the original dictionary due to a bit of trickery in the NSDictionary class cluster for efficiency reasons. Try running analyse over your code, it should point these things out to you.

Categories

Resources