What am I doing wrong in my code? - objective-c

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.

Related

NSKeyedArchiver fails to archive an NSString

What I'm trying to do is simply:
NSArray *dirs = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
NSString *d = [dirs[0] stringByAppendingPathComponent:#"test.archive"];
BOOL r = [NSKeyedArchiver archiveRootObject:d toFile:d];
NSLog(#"%d", r);
And the code fails every time (meaning log shows 0, and no file is created in the corresponding file path).
What am I missing here?
NSArray *dirs = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
I think you mean NSDocumentsDirectory, not NSDocumentationDirectory. Try logging d as well as r to see what path you're trying to write to. As is I think you'll get (null).

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"]]];

App crashes when deleting first item from plist (UITableView)

In want to delete rows from my UITableView. The UITableview gets it data from a plist. So when i delete a row i tell the app to delete the corresponding item in the plist (in this case a dictionary. One item of the dictionary (Name) is the title of the UITableViewCell, so the plist looks like so:
Dictionary
KEY(Name)
ITEM
KEY(Description)
ITEM
Dictionary
KEY(name)
....
)
And i use the following code to delete the rows, it works fine, apart from the very first row. The app crashes when i try to delete the first row, i have no idea why.
int g = indexPath.row;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"data.plist"];
NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:path];
[array removeObjectAtIndex:g];
[array writeToFile:path atomically:YES];
EXC_BAD_ACCESS usually means that the program tried to use an object that had already been deallocated.
I doubt that such object could be array, since it has just been allocated when you try and remove its 0-th element. You could easily check this by adding an NSLog trace like here:
NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:path];
NSLog(#"Array count: %d", [array count]);
[array removeObjectAtIndex:g];
In general, to determine which object could be, my suggestion is enable NSZombies. You can do that by running the app using the "Zombies" performance tool, or setting an environment variable.
You will get a much more descriptive error message that will also identify the type of object that you tried to access.

Problem to write into plist

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.

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