Problem to write into plist - objective-c

Helle everyone,
I have copied my plist into Sandbox (FileManager) and now I'm able to change plist's values.
I'm trying to do that but it doesn't work.
Here is my plist structure :
and my snippet
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:#"BlogList.plist"];
NSMutableDictionary *ressourceDico = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath];
NSArray *ressourceArray = [NSArray arrayWithArray:[ressourceDico objectForKey:#"BlogList"]];
for(int i = 0; i < [ressourceArray count] ; i++)
{
NSMutableDictionary *dico = [ressourceArray objectAtIndex:i];
if(![[dico objectForKey:#"isSaved"] boolValue] && [[dico objectForKey:#"identifier"] isEqualToString:identifier])
{
[dico setObject:[NSNumber numberWithBool:YES] forKey:#"isSaved"];
[dico writeToFile:plistPath atomically:YES];
}
}

You can't write just a part of the dictionary into the file, in order to 'update' just a part of it. Instead you have to, write the whole dictionary into the file.
So I think, you will have to send writeToFile:atomically: after looping over the array elements, but the reciever might be ressourceDico instead of dico.

Related

Storing data from a plist file into an array

I have spent all of yesterday trying to figure this out with no luck at all. Here is the code im working with.
NSString *path = [[NSBundle mainBundle] pathForResource:#"file" ofType:#"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
NSArray *array = [NSArray arrayWithArray:[dict objectForKey:#"root"]];
for(int num = 0; num < 5; num++)
{
NSLog(#"my array:%#", array);
}
NSLog(#"items in my array: %lu", (unsigned long) [array count]);
Here are the views for the plist file im working with.
<plist version="1.0">
<dict>
<key>New item</key>
<string>hello</string>
<key>New item - 2</key>
<string>world</string>
<key>New item - 3</key>
<string>again</string>
<key>New item - 4</key>
<string>and</string>
<key>New item - 5</key>
<string>again</string>
</dict>
</plist>
This code does not return null like when i tried using an NSArray over the NSDictionary, but when i run it console does not print out any data retrieved from the plist. It just prints out:
my array:{}
my array:{}
my array:{}
my array:{}
my array:{}
items in my array: 0
If i try to print out dict by changing the NSLog to NSLog(#"my array:%#", array); i get this.
my array:(NULL)
my array:(NULL)
my array:(NULL)
my array:(NULL)
my array:(NULL)
items in my array: 0
Everything you could print for such plist is
NSLog(dict[#"new item"]);
Also you probably should use
for(int num = 0; num < array.count; num++)
{
NSLog(#"my array:%#", array[i]);
}
instead of
for(int num = 0; num < 5; num++)
{
NSLog(#"my array:%#", array);
}
Don't know what keys are in dictionary? No need to concern about keys in this case. Try this
NSString *path = [[NSBundle mainBundle] pathForResource:#"file" ofType:#"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
if(dict.count != 0)
{
NSArray *array = [dict allKeys];
for(int num = 0; num < array.count; num++)
{
NSLog(#"my array item:%#", [dict objectForKey:array[num]]);
}
}
else
{
NSLog(#"Your dictionary is empty.");
}
Are you trying to put all the values form the dict into the array ?
If so add:
NSArray *array = [NSArray arrayWithArray:[dict allValues]];
//Check for file;
NSString *path = [[NSBundle mainBundle] pathForResource:#"file" ofType:#"plist"];
if (![[NSFileManager defaultManager] fileExistsAtPath:path])
NSLog(#"NO FILE AT PATH: %#", path);
I found the issue. I had to create a build phase and add the plist files to it. That way when i use the pathToResource ofFile it has a file to find when i use the rest of the code.

How do I initialize all positions in an array of numbers?

I want to store the same number in an array 100 times. These numbers will change later on, but I want to write an if statement using a counter to populate all 100 slots initially with the value of 0. Is there an easy way to do this?
Something like this, where 'block01' needs to change to 'block02', 'block03' etc.:
int block01 = 0;
NSMutableDictionary* myDict = [[NSMutableDictionary alloc] init];
if(myDict)
{
[myDict setObject:block01 forKey:#"block01stored"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath = [paths objectAtIndex:0];
NSString *path = [documentPath stringByAppendingPathComponent:#"blocks.save"];
BOOL successfulWrite = [myDict writeToFile: path atomically: YES];
if(successfulWrite == NO)
}
This should help you. It's a loop that will execute 99 times (1 - 100) adding zero as the object for a key formatted to include the current number.
NSMutableDictionary* myDict = [[NSMutableDictionary alloc] init];
for (int i = 1; i <= 100; i ++) {
if(myDict)
{
[myDict setObject:[NSNumber numberWithInt:0] forKey:[NSString stringWithFormat:#"block%.3istored",i]];
}
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath = [paths objectAtIndex:0];
NSString *path = [documentPath stringByAppendingPathComponent:#"blocks.save"];
BOOL successfulWrite = [myDict writeToFile: path atomically: YES];
if(successfulWrite == NO)
EDIT: To get the value for a certain key you can use the following:
int myInt = [[myDict objectForKey:#"block050stored"] intValue];
And if you want to replace the object for a certain key it's as easy as:
[myDict setObject:[NSNumber numberWithInt:1] forKey:#"block020stored"];
Now, the %.3i tells the string to add a number (i) formatted to always be three digits long. (000, 001, 010, 099, 100)
[NSString stringWithFormat:#"block%.3istored",i]
So the above line basically means, create a string with the words "block" and "stored" with a three digit representation of what ever the current value of the int "i" is in between them.
You can create NSNumber (which is an object, but int is not) and then store it into NSMutableDictionary:
NSNumber* num = [NSNumber numberWithInt:0];
for (int i = 1; i<=100; i++) {
[myDict setObject:num forKey:[NSString stringWithFormat:#"block%dstored",i]];
}

save CLLocation to a plist

I'm struggling to save several locations into a plist file for later use,
after a bit of googling I discovered that an array of CLLocation per se cannot be saved,
so I was wondering about a way to do it.
I was thinking about a couple of classes to "serialize"/"deserilize" a single CLLocation object into an NSDictionary and then store an array of those NSDictionaries into the plist file, but I was wondering if there could be a better/smarter/reliable way to achieve that.
thanks in advance.
EDIT:
this is the function I use to save the data in the plist (the c_propertyName takes the code from the answer)
- (void) addLocation {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"/Locations.plist"];
NSArray *keys = [curLocation c_propertyNames];
NSDictionary *dict = [curLocation dictionaryWithValuesForKeys:keys];
[dict writeToFile: path atomically:YES];
}
EDIT 2 — SOLUTIONS:
Ok, I've figured all out. right below, I've posted a two-optioned solution to my own question.
It's quite easy with KVC.
Here's method of NSObject category to get property names (requires <objc/runtime.h>)
- (NSArray *)c_propertyNames {
Class class = [self class];
u_int count = 0;
objc_property_t *properties = class_copyPropertyList(class, &count);
if (count <= 0) {
return nil;
}
NSIndexSet *set = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, count)];
NSMutableSet *retVal = [NSMutableSet setWithCapacity:count];
[set enumerateIndexesWithOptions:NSEnumerationConcurrent
usingBlock:^(NSUInteger idx, BOOL *stop) {
const char *propName = property_getName(properties[idx]);
NSString *name = [NSString stringWithUTF8String:propName];
[retVal addObject:name];
}];
return [retVal allObjects];
}
then use it like this :
NSArray *keys = [yourLocation c_propertyNames];
NSDictionary *dict = [yourLocation dictionaryWithValuesForKeys:keys];
then save that dictionary.
I like solution 2 but serialization can be simpler if all one is trying to do is write straight to a file.
[NSKeyedArchiver archiveRootObject:arrayOfLocations toFile:path];
after some hours of search I've figured out the entire scenario.
Here you got a couple of solutions; the first is the more "dirty", because it's the first I've came up with, while the second is the more elegant. Anyway, I'll leave'em both because maybe they could both come in handy to somebody.
S O L U T I O N — 1
Thanks to the help of mit3z I could put together the pieces to figure out a solution.
as he points out, you can implement this method into a category on the NSObject:
- (NSArray *)c_propertyNames;
( look at his response for this part's code and further more details about it )
this gives me the liberty to do such thing:
- (void) addLocation {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"/Locations.plist"];
NSArray *keys = [curLocation c_propertyNames]; // retrieve all the keys for this obj
NSDictionary *values = [self.curLocation dictionaryWithValuesForKeys:keys];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
for(NSString *key in keys) {
NSString *aaa = [NSString stringWithFormat:#"%#", (NSString *)[values valueForKey:key]];
[dict setValue:aaa forKey:key];
}
[dict writeToFile:path atomically:YES];
}
the superdumb for loop is needed to convert all the data in the NSDictionary into NSStrings so that they can be written into the plist file without troubles, if you just make the dictionary and then you attempt to save it right away, you wan't succeed.
In this way I can have all the CLLocation obj "serialized" into a dict and then written into a plist file.
S O L U T I O N — 2
I came up with a really easiest (and more elegant) way to do so: using the NSCoding.
Because of the fact (that I realized that)the CLLocation datatype conforms NSCoding, you can invoke the data archiver via NSKeyedArchiver to get a blob describing your array and then store it right to the plist, like that:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"/Locations.plist"];
NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
[data setValue:[NSKeyedArchiver archivedDataWithRootObject:arrayOfLocations] forKey:#"LocationList"];
[data writeToFile:path atomically:YES];
[data release];
and voila'. simple as that! :)
based on the same principles you can easily get back your data, via NSKeyUnarchiver:
self.arrayOfLocations = [[NSMutableArray alloc] initWithArray:[NSKeyedUnarchiver unarchiveObjectWithData: (NSData *)[dict objectForKey:#"LocationList"]]];

How do I write an IF ELSE to check string contents of an array?

I'm trying to write an IF ELSE statement to enable shipping, If user doesn't add an address the array contents remain as "-" & "-" for the two items in the array. I want to check to see if those are in the array, if they are then I want to enableshipping.
Here is the code for getting the array:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullFileName = [NSString stringWithFormat:#"%#/arraySaveFile", documentsDirectory];
NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:fullFileName];
How do I write this first line to look for the "-" & "-"?
if ([fullFileName isEqualToString:#"-","-"])
{
[nnNEP EnableShipping];
}
else {
[nnNEP DisableShipping];
}
Thanks,
michael
I think you want to check the contents of the first two items of the array and not fullFileName.
For example:
if ([[array objectAtIndex:0] isEqualToString:#"-"]
&& [[array objectAtIndex:1] isEqualToString:#"-"])
{
[nnNEP EnableShipping];
}
else
{
[nnNEP DisableShipping];
}

What am I doing wrong in my code?

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *myPlistPath = [documentsDirectory stringByAppendingPathComponent:#"Accounts.plist"];
NSArray *arr = [NSArray arrayWithContentsOfFile:myPlistPath];
int count = 0;
for (NSDictionary *dict in arr) {
count += dict.count;
}
return count;
What am I doing wrong?
I get the following error with the above code: Program received signal: “EXC_BAD_ACCESS”.
EXC_BAD_ACCESS is usually a memory fault, possibly caused by a bad address.
Start by printing out paths, documentsDirectory, myPListPath and arr (the addresses, not the contents) immediately after you set them, to see if any of them have been set to NULL.
Try printing out myPListPath and verifying that the file it's referring to actually exists and is the correct format. If you ask me, chances are that on this line:
NSArray *arr = [NSArray arrayWithContentsOfFile:myPlistPath];
something is going wrong, and arr is getting set to null.