NSCFArray objectForKey crash? - ios

I am trying to do something relatively simple. I have a .plist in my bundle and I am trying to save it to the documents directory with encryption. Now before I tried added encryption, it worked fine. However a new crash has arose.
This is how I save my .plist:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Hi.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path]) {
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"GameSave" ofType:#"plist"];
NSData *plistData = [NSData dataWithContentsOfFile:bundle];
[NSKeyedArchiver archiveRootObject:plistData toFile:path];
plistData = [plistData AES256EncryptWithKey:#"536335"];
[plistData writeToFile:path atomically:YES];
}
Then this is how I retrieve my .plist (and later change a value and re-save)
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Hi.plist"];
//Get array and then current level dict
NSData *plistData = [[NSData alloc] initWithContentsOfFile:path];
plistData = [plistData AES256DecryptWithKey:#"1111"];
NSMutableArray *savegameArray = [[NSKeyedUnarchiver unarchiveObjectWithData:plistData] mutableCopy];
int objectIndex = [Singleton sharedInstance].levelNumber - 1;
NSMutableDictionary *levelDict = [[savegameArray objectAtIndex:objectIndex] mutableCopy];
[levelDict setObject:videoID forKey:#"RecordingURL"];
//Now put new dict back in array
[savegameArray replaceObjectAtIndex:objectIndex withObject:levelDict];
NSData *savedarrayData = [NSKeyedArchiver archivedDataWithRootObject:savegameArray];
savedarrayData = [savedarrayData AES256EncryptWithKey:#"1111"];
[savedarrayData writeToFile:path atomically:YES];
However, in the read code every time I get to this line: NSMutableArray *savegameArray = [[NSKeyedUnarchiver unarchiveObjectWithData:plistData] mutableCopy]; There is a SIGABRT crash which prints:
'-[__NSCFArray objectForKey:]: unrecognized selector sent to instance
0x16604140'
What am I doing wrong?

As we discovered through our chat, we had to first convert the decrypted NSData object to a proper NSPropertyListSerialization serialization.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Hi.plist"];
NSData *plistData = [[NSData alloc] initWithContentsOfFile:path];
NSData *newData = [plistData AES256DecryptWithKey:#"1111"];
NSPropertyListFormat format;
NSMutableArray *savegameArray = [[NSPropertyListSerialization propertyListFromData:newData mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:nil]mutableCopy];
NSLog(#"Array: %#",savegameArray);

You just need to allocate memory to your NSMutableArray like...
NSMutableArray *arrayName = [[NSMutableArray alloc] init];
Until you do that crash will arose..
Hope this is helpful.
Thanks,
Rajesh..

Related

Saving image and its title on plist

How can I store an image and any string value in plist as dictionary.I
have created a plist file in the project,and
also how can i append the file with same dictionary of different image and name?
Use the following code to write image & title to-gather in plist-
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"PlistName.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path])
{
path = [documentsDirectory stringByAppendingPathComponent: [NSString stringWithFormat: #"PlistName.plist"] ];
}
fileManager = [NSFileManager defaultManager];
NSMutableDictionary *dataDictionary=[NSMutableDictionary alloc] init];
[dataDictionary setObject:ImageData forKey:image];
[dataDictionary setObject:ImageTitle forKey:title];
[dataDictionary writeToFile: path atomically:YES];
And read your image & title dictionary from plist like this-
- (NSDictionary * )readDataFromPlist()
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"PlistName.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSMutableDictionary *dataDictionary;
if ([fileManager fileExistsAtPath: path])
{
dataDictionary = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
return dataDictionary;
}else
return nil;
}
You can follow this link. It provides detail how to store image to plist
Storing image in plist
And for title to store you can add new key like below.
// Get a full path to a plist within the Documents folder for the app
NSString *titleStr = #"Title Of Image";
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *path = [NSString stringWithFormat:#"%#/YOURPLIST.plist",
[paths objectAtIndex:0]];
// Place an image in a dictionary that will be stored as a plist
[dictionary setObject:image forKey:#"image"];
[dictionary setObject:titleStr forKey:#"title"];
// Write the dictionary to the filesystem as a plist
[NSKeyedArchiver archiveRootObject:dictionary toFile:path];

How can I access my plist in another viewcontroller?

I have one 3 arrays that i am trying to save to 3 different plists in one view and then load that data into an array in another view. I am having trouble figuring out how to access the data in the plist in my other view and save it correctly in my initial view. Here is the code from my first view.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [documentPaths objectAtIndex:0];
NSString *documentsDirectory1 = [documentPaths objectAtIndex:1];
NSString *documentsDirectory2 = [documentPaths objectAtIndex:2];
NSString *documentsDirectory3 = [documentPaths objectAtIndex:3];
NSString *documentPlistPath1 = [documentsDirectory stringByAppendingPathComponent:#"balance.plist"];
NSString *documentsPlistPath2 = [documentsDirectory1 stringByAppendingPathComponent:#"principal.plist"];
NSString *documentsPlistPath3 = [documentsDirectory2 stringByAppendingPathComponent:#"interest.plist"];
NSString *documentsPlistpath4 = [documentsDirectory3 stringByAppendingPathComponent:#"dates.plist"];
[dateValues writeToFile:documentsPlistpath4 atomically:YES];
[balanceLabels writeToFile:documentPlistPath1 atomically:YES];
[pricipalLabels writeToFile:documentsPlistPath2 atomically:YES];
Any help is greatly appreciated!
Thanks!
create an array
NSArray *array = #[#"abc", #"cba"];
get path to plist file
NSString *documentsFolderPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *fileName = #"my_plist_file";
NSString *filePath = [documentsFolderPath stringByAppendingPathComponent:fileName];
save an array to .plist
[array writeToFile:filePath atomically:YES];
read an array from .plist
NSArray *arrayFromDisk = [NSArray arrayWithContentsOfFile:filePath];

writeToFile:atomically: not saving new plist data

I am using writeToFile:atomically: to update the value of a key in my plist by 1 every time the app is launched. I put this code in viewDidLoad, which reads the string value of the key, gets the numeric value of that string, increases it by 1, converts it back to a string, and writes that as the new string for that key, but when I read it again it seems to have not updated. I can't figure out what I'm doing wrong. I don't need a special framework for writeToFile:atomically:, do I?
Here is the code:
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"DaysLaunched.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"DaysLaunched" ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath:path error:&error];
}
NSMutableDictionary *plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
NSMutableDictionary *data1 = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
NSString *currentNumberOfDays = [NSString stringWithFormat:#"%#",[plistDict objectForKey:#"numberOfDays"]];
NSLog(#"currentNumberOfDays = %#", currentNumberOfDays); //0
int days = [currentNumberOfDays intValue];
days ++;
currentNumberOfDays = [NSString stringWithFormat:#"%d", days];
[data1 setObject:[NSString stringWithFormat:#"numberOfDays"] forKey:currentNumberOfDays];
NSLog(#"currentNumberOfDays = %#", currentNumberOfDays); //1
[data1 writeToFile: path atomically:YES];
currentNumberOfDays = [NSString stringWithFormat:#"%#",[plistDict objectForKey:#"numberOfDays"]];
NSLog(#"currentNumberOfDays = %#", currentNumberOfDays); //0 ??????? writeToFile isn't working?
And here is a screenshot of "DaysLaunched.plist" in my 'Supporting Files' folder, (I've also verified that the plist file name is spelled exactly the same way I spelled it in my code, via Copy-Paste)
The original plist file is also in my 'Copy Bundle Resources' in targets.
Try
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"DaysLaunched.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"DaysLaunched"
ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath:path error:&error];
}
NSMutableDictionary *plistDict = [NSMutableDictionary dictionaryWithContentsOfFile:path];
NSInteger days = [plistDict[#"numberOfDays"] integerValue];
plistDict[#"numberOfDays"] = [#(++days) stringValue];
[plistDict writeToFile: path atomically:YES];
You have made a mistake while setting your data.
You should do:
[data1 setObject:currentNumberOfDays forKey:#"numberOfDays"];
instead of:
[data1 setObject:[NSString stringWithFormat:#"numberOfDays"] forKey:currentNumberOfDays];

How to retrieve an array of images from a plist file which is shown in an imageview?

How do I retrieve image data from plist and display to that data to an image view?
- (void)getImages {
// Look in Documents for an existing plist file
NSArray *paths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
myPlistPath = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithFormat: #"%#.plist", plistName] ];
[myPlistPath retain];
// If it's not there, copy it from the bundle
NSFileManager *fileManger = [NSFileManager defaultManager];
if ( ![fileManger fileExistsAtPath:myPlistPath] ) {
NSString *pathToSettingsInBundle = [[NSBundle mainBundle]
pathForResource:plistName ofType:#"plist"];
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [paths objectAtIndex:0];
NSString *path = [documentsDirectoryPath
stringByAppendingPathComponent:#"myApp.plist"];
NSMutableDictionary *plist = [NSDictionary dictionaryWithContentsOfFile: path];
NSArray *imageArray = [plist objectForKey:#"imageArray"];
for (NSString *imageString in imageArray) {
DLog(#"Image Name: %#", imageString);
}
}
Get plist code from www.iphoneexamples.com

is it possible to save NSMutableArray or NSDictionary data as file in iOS?

I want to save an NSMutableArray or NSDictionary as a permanent file. Then, I would like to reopen the file later.
Is this possible? If so, how can I do it?
To write in file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:FILE_NAME];
[myArray writeToFile:filePath atomically:YES];
To read from file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:FILE_NAME];
myArray = [NSArray arrayWithContentsOfFile:filePath];
myArray will be nil if file is not present. And NSDictionary has similar methods. Please check the reference for the details of these methods.
May be you can convert a Dictionary to JSON data.and write it to a file.
NSDictionary *dict = /* the NSDictionary/NSArray you need to write */
NSError *writeError = nil;
NSData* data;
data = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&writeError];
if (!writeError) {
[data writeToFile:filePath atomically:YES];
}

Resources