NSKeyedArchiver fails to archive an NSString - objective-c

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).

Related

How to get a filepath from a directory without file name in iOS Objective c

Good day
How do you get a filePath without fileName from a fullpath.
Lets say I have a path:
NSString *myPath = #"/Users/myName/Library/Developer/CoreSimulator/Devices/.../Library/Caches/Getting Started.pdf";
and I want to just have
NSString *newPath = #"/Users/myName/Library/Developer/CoreSimulator/Devices/.../Library/Caches";
I didnt want to substring it, I hope there is a better solution.
Thank you in advance.
Check the class reference for NSString.
newPath = [path stringByDeletingLastPathComponent];
try this code
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSLog(#" DocumentPath %#",documentPath);

How to Store a Hex Value in a Plist and read in back out again

If been trying to figure this out for ages now and my mind is gone to mush.
What I want to do is store a hex value in NSData in a plist.
I then want to be able to read the hex back out.
I have gotten very confused.
So I try to store the hex value 0x1124.
When I look in the plist that gets made the value says 24110000.
And When I print this value I get 23FA0
What I want to be able to do is confirm that 0x1124 gets written to my plist and make sure I can print back out the right value.
Im getting the feeling that Im lacking some very fundamental stuff here.
NSMutableDictionary *tempDict=[NSMutableDictionary new];
// Byte hidService= 1124;
//int hidService= 00001124-0000-1000-8000-00805f9b34fb
unsigned int hidService[]={0x1124};
NSData *classlist=[NSData dataWithBytes:&hidService length:sizeof(hidService)];
NSArray *classListArray=#[classlist];
[tempDict setValue:classListArray forKey:kServiceItemKeyServiceClassIDList];
hidProfileDict=[[NSDictionary alloc]initWithDictionary:tempDict];
NSLog(#"%X",[hidProfileDict valueForKey:kServiceItemKeyServiceClassIDList][0]);
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSFileManager *fileManager=[NSFileManager defaultManager];
NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:#"HIDDictionary.plist"];
if (![fileManager fileExistsAtPath: plistPath])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"HIDDictionary" ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath:plistPath error:&error];
}
[hidProfileDict writeToFile:plistPath atomically: YES];
0x1124 is just a hex representation of the binary bits 0001000100100100 or decimal number 4388. The 0x is just a way to designate the base of the display, it is not part of the number. The number could be expressed in a program in binary with a 0b prefix: int b = 0b0001000100100100;. These are all just different representations of the same number.
To add a number to a NSDictionary or NSArray you need to convert it to an NSNumber, the easiest way is to use literal syntax: #(0x1124) or #(4388).
Ex:
NSArray *a = #[#(0x1124)];
or
NSDictionary *d = #{kServiceItemKeyServiceClassIDList:#(0x1124)};
// Where kServiceItemKeyServiceClassIDList is defined to be a `NSString`.
If you want to store only two bytes use an explicit UInt16 type
UInt16 hidService[]={0x1124};
NSData *classlist = [NSData dataWithBytes:&hidService length:sizeof(hidService)];

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

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.

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.