I have a plist that looks like the following.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!--
Translations
-->
<plist version="1.0">
<array>
<dict>
<key>English</key> <string>Hello Mrs./Mr./Miss.</string>
<key>French</key> <string>Bonjour Madame / Monsieur / Mademoiselle.</string>
<key>Spoken</key> <string>Boh(n)-zhoor mah-dahme/ muh-syuhr/ mah-dah-mwa-sell.</string>
</dict>
<dict>
<key>English</key> <string>Excuse me.</string>
<key>French</key> <string>Pardon.</string>
<key>Spoken</key> <string>Par-doh(n).</string>
</dict>
<dict>
<key>English</key> <string>Do you speak English?</string>
<key>French</key> <string>Parlez-vous anglais?</string>
<key>Spoken</key> <string>Par - lay vooz ah(n)-glay?</string>
</dict>
</array>
</plist>
I want to know how to find how many elements are in the plist. For example, there is 3 in the code above. Is there an attribute of plist I can call to find this number?
Read the plist into an array:
NSArray *plistArray = [NSArray arrayWithContentsOfFile:pathToPlistFile];
and count the number of elements:
NSUInteger count = [plistArray count];
I am writing a tweak for jailbroken iOS devices and I want to be able to write this NSString "bundleID" and the integer created in my code to a plist file. The code below can do this, however, it only does this once and doesn't allow me to write it to the plist multiple times. I want to do this because the bundleID changes and should also be written to the plist. Basically what I want to do is when an app is launch the bundle id for that app (com.apple.mobilesafari) is written as the key in my plist. I then have code to work add 1 to the value every time the app is opened. So for example if I opened mobile safari four times the plist should look like this.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.mobilesafari</key>
<integer>4</integer>
<key>customText</key>
<false/>
<key>enabled</key>
<false/>
</dict>
</plist>
However, when I launch mobile safari four times it stays as...
<key>com.apple.mobilesafari</key> <integer>1</integer>
I also want the bundleID saved for every app. So if I open safari then contacts I want both in my plist. For example...
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.mobilesafari</key>
<integer>1</integer>
<key>customText</key>
<false/>
<key>enabled</key>
<false/>
</dict>
<dict>
<key>com.apple.contacts</key>
<integer>1</integer>
<key>customText</key>
<false/>
<key>enabled</key>
<false/>
</dict>
</plist>
Here is my objective-c code...
%hook SBApplicationIcon
-(void)launch
{
// Return original method
%orig;
// Get Bundle ID
NSString* bundleID = [self leafIdentifier];
// Print that badboy!
NSLog(#"Bundle ID: %# ",bundleID);
// Set up plist
NSMutableDictionary *launches = [[NSMutableDictionary alloc] initWithContentsOfFile:#"/var/mobile/Library/Preferences/com.bengerard.ipslider.plist"];
// Check plist exists
NSString *pathToFile = #"/var/mobile/Library/Preferences/com.bengerard.apppop.plist";
BOOL isFile = [[NSFileManager defaultManager] fileExistsAtPath:pathToFile isDirectory:NO];
if(isFile)
{
// Counting
int count = [[launches objectForKey:bundleID] intValue];
count++;
// Write number of launches to plist
[launches setObject:[NSNumber numberWithInt:count] forKey:bundleID];
//[launches insertObject:[NSNumber numberWithInt:count] forKey:bundleID];
[launches writeToFile:#"/var/mobile/Library/Preferences/com.bengerard.apppop.plist" atomically:YES];
}
else {
//The file doesn't exit.
}
// [bundleID release];
// [pathToFile release];
// [launches release];
}
%end
P.S: I am also using theos by DHowett to compile my tweak.
Edit: Realised my two plists are different. Probably causing my problem. I will test later
I am writing an app that copies a plist into the docsdir and then reads it into a mutable array. The code below, however, returns a count of 0 for the array. The line with the dictionary log, however, returns the correct items. I have also verified that the file is being copied to the docsdir.
-(NSString *)docsDir {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *listPath = [[self docsDir]stringByAppendingPathComponent:#"list.plist"];
if (![[NSFileManager defaultManager]fileExistsAtPath:listPath]) {
[[NSFileManager defaultManager]copyItemAtPath:[[NSBundle mainBundle]pathForResource:#"list" ofType:#"plist"] toPath:listPath error:nil];
NSLog(#"Chicken");
}
NSLog(#"%#", [NSDictionary dictionaryWithContentsOfFile:listPath]);
_array = [NSArray arrayWithContentsOfFile:listPath];
NSLog(#"Count: %i", [_array count]);
}
- (void)viewDidUnload
{
[super viewDidUnload];
/ / Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
Usually this is because by default root element in plist files is a Dictionary.
Right click and select Open as Source Code, your file may look like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>foo</key>
<array>
<string>foo1</string>
<string>foo2</string>
<string>foo3</string>
</array>
</dict>
</plist>
where the root element is a dict, change it to:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<string>foo1</string>
<string>foo2</string>
<string>foo3</string>
</array>
</plist>
where the root element is an array. You can now edit as usual.
Open the plist file with Xcode.
Just find the 'key' at the top left corner and Type of the plist.
Make sure the Type is Array.
I think your plist is a dictionary that contains an array.
Try this
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:listPath]
NSArray *array = [dict objectForKey:#"key"];
Plists are usually saved a dictionaries:
Here's an example :
<dict>
<key>tiltingAnim</key>
<dict>
<key>filenamePrefix</key>
<string>radar_</string>
<key>delay</key>
<real>0.25</real>
<key>animationFrames</key>
<string>1,2,3,4,5,5,4,3,2,1,2,3,4,5</string>
</dict>
<key>takingAHitAnim</key>
<dict>
<key>filenamePrefix</key>
<string>radar_</string>
<key>delay</key>
<real>0.1</real>
<key>animationFrames</key>
<string>5,5,7,8,8</string>
</dict>
<key>blowingUpAnim</key>
<dict>
<key>filenamePrefix</key>
<string>radar_</string>
<key>delay</key>
<real>0.2</real>
<key>animationFrames</key>
<string>5,6,7,8,9,10,11,12,13,14,15,16,17</string>
</dict>
<key>transmittingAnim</key>
<dict>
<key>filenamePrefix</key>
<string>radar_</string>
<key>delay</key>
<real>0.3</real>
<key>animationFrames</key>
<string>5,6,5,6,5,6,5</string>
</dict>
</dict>
Now, there are 2 solutions to your question.
Either get the contents into a dictionary then take out the array for a specific key.
Open up the plist with a text editor and change the root key into then change root into . If your plist is static and in the bundle resources then you could do this but if it's a plist generated by your code then i wouldn't recommend this.
I am using the route me frame work for my map application.
I badly want to cache more tiles than its caching by default.
So i changed the routeme.plist like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>capacity</key>
<integer>16</integer>
<key>type</key>
<string>db-cache</string>
</dict>
<dict>
<key>capacity</key>
<integer>100000</integer>
<key>minimalPurge</key>
<integer>5000</integer>
<key>strategy</key>
<string>LRU</string>
<key>type</key>
<string>memory-cache</string>
<key>useCachesDirectory</key>
<true/>
</dict>
</array>
</plist>
But it doesn't matter which values i change, the app always reloads tiles which i have already seen before. Is there a limit for caching?
I'm trying to use a deeply nested data structure and NSPredicate to filter that data.
I have a plist file like this:
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>images-ipad</key>
<array>
<dict>
<key>categories</key>
<array>
<string>standard</string>
</array>
<key>name</key>
<string>Default</string>
<key>plist</key>
<string>cardSheet.plist</string>
<key>png</key>
<string>cardSheet.png</string>
</dict>
<dict>
<key>categories</key>
<array>
<string>standard</string>
</array>
<key>name</key>
<string>Optional</string>
<key>plist</key>
<string>cardSheet.plist</string>
<key>png</key>
<string>cardSheet.png</string>
</dict>
<dict>
<key>categories</key>
<array>
<string>christmas</string>
<string>holiday</string>
<string>standard</string>
</array>
<key>name</key>
<string>christmas</string>
<key>plist</key>
<string>cardSheet.plist</string>
<key>png</key>
<string>cardSheet.png</string>
</dict>
</array>
</dict>
</plist>
Which I load into an NSDictionary via dictionWithContentsOfFile.
I then want to get the elements of the array images-ipad that are in the category 'standard' via NSPredicate. I think this is possible, but I've not been able to accomplish it, and the docs don't seem to cover nested data structures.
So, I've tried this:
NSPredicate *getcat = [NSPredicate predicateWithFormat:#"ANY images-ipad.categories == 'holiday'"];
NSArray *res = [[dict objectForKey:#"images-ipad"] filteredArrayUsingPredicate:getcat];
but it does not return any elements, which brings me to stackoverflow. Thanks in advance.
Since you're filtering the result of [dict objectForKey:#"images-ipad"], you shouldn't include that string in the key path of the predicate, as it's basically equivalent to looking up images-ipad.images-ipad.categories, which doesn't exist.