Suppose I have an model object class Box. In my Box class I add images references (png), audio (mp3) etc...
Rather than store them as NSData it seems better to reference the paths to the files...to save memory.
I would like archive this Box class. On the desktop we would use Document Packages (NSFilewrapper). But this class is not part of the Iphone OS.
Any suggestions on archiving this class and including all the files as 'document package'? This is similar to the way Applications appear as a file but are actually a folder...
Thanks!
If you really need to save the objects in Box, I would load them into an NSDictionary and the write that out:
Note: this is untested/non-production code intended to be a starting point only.
- (BOOL)saveBox:(Box*)aBox;
{
NSMutableDictionary *boxDict = [NSMutableDictionary dictionaryWithCapacity:10];
// Add contents of box to dictionary (exercise left up to original poster)
// boxDict is now populated
// write dictionary to apps document directory.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
if (!documentsDirectory) {
NSLog(#"Documents directory not found!");
return NO;
}
// Assumes Box class has name property
NSString *outputFile = [documentsDirectory stringByAppendingPathComponent:[aBox name]];
return [boxDict writeToFile:outputFile atomically:YES];
}
This could easily be modified to return the name of the file, etc. based on your needs.
Related
I have a view responsible for recording audio. How can i record several audios and show them in a table view?
I'm trying to use docs directory to save the recorded audios:
NSArray *folders = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *documentsFolder = [folders objectAtIndex:0];
NSString *recordedAudio = [documentsFolder stringByAppendingPathComponent:newAudio];
newAudio is a string that contains new audio name typed by the user with the suffix .m4a.
To retrieve the saved audios i'm trying something like this:
NSArray *folders = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsFolder = [folders objectAtIndex:0];
NSArray *folderContents = [[NSArray alloc] initWithContentsOfFile:documentsFolder];
I expected folderContents would have all the audios stored at documentsFolder so a could load my table, but its count is 0. I'm new in docs directory, probably i'm missing something, or doing all wrong.
What is wrong, or there is another way to accomplish that?
You are getting the contents of the documents directory incorrectly. This is the right way:
NSArray *folderContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsFolder error:nil];
Documents is not a file, it is a folder.
edit: This is how you save a file
Assuming you have an NSData object such as
NSData *audioData = ...; // initialiazed with your recording
After you create your recordedAudio string, which is actually just the filename you want to write to (should probably called audioPath or something), you need to add this:
[audioData writeToFile:recordedAudio atomically:YES];
I use NSKeyedArchiver to archive data in my iPhone app into a .data. Long story, short, I lost all my data. I use "iPhone back up extractor" and it works great. I found a .data file for my app.
To be clear, I found a .data file and I would to open and see what the contents look like. I understand no software (Ex: notepad) might be able to read that file and I may have to use Xcode. If you know of any way, Xcode/notepad/someProgram, please let me know.
This is the code that I implement when I build the app:
- (NSString *)locPath {
return pathInDocumentDirectory(#"tableArray.data");
}
- (void)archieve{
// Get the path to the document directory
NSString *path = [self locPath];
// grab the array
NSMutableArray *tableArray = [someViewController tableArray];
// archive the array to file
[NSKeyedArchiver archiveRootObject:tableArray toFile:path];
}
This code is called during applicationWillTerminate, applicationDidEnterBackground, etc...
The data is restored/called upon in the didFinishLaunchingWithOptions like this:
// Get the path to the document directory
NSString *path = [self locPath];
// Unarchive .data into an array
NSMutableArray *tableArray = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
Any help is appreciated! Thanks!!!
PS: Link for iPhone back up extractor is http://supercrazyawesome.com/
The easiest way I found is to get the document directory using this code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *dir = [paths objectAtIndex:0];
NSLog(#"Directory: %#", dir);
In there, the Documents dir will contain the .data file
I have interesting thing here, I'm using xcode 4 for my project and I want to create simple .plist file to save several values which will be used for different purposes during code execution. This is the code I use to create plist:
- (NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:#"somelist.plist];
}
last line of code which should append plist name to path do not do its job. Plist is never created. Now, strange thing, i manage to create one few days ago using same code. After that, I only move this piece of code in AppDelegate because, I call this code from different places. I discovered that isn't working when I switch to 4.3 emulator and then also try it on iphone device. When I switch to 4.2 emulator it works because there is already a plist, however when I change its name (to create new one) nothing happens - meaning, list is not created. I also try moving code back to original place, but that didn't gave desired result.
Your code should not create a plist anyway, only return a path. In order to actually save a plist at the chosen path, you could choose several approaches, for example use the following method on NSDictionary:
- (void)saveDictionary
{
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:#"bla" forKey:#"test"];
NSString *path = [self datafilePath];
[dictionary writeToFile:path atomically:YES];
}
- (NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:#"somelist.plist];
}
I have a NSMutableArray, each item in this array is different class. In each class has many field such as CPPlot, identifier,... (I am using CorePlot to develop a stock application). Now I would like to store this NSMutableArray to load when user reopen application, this will load all the chart they used before.
I try to figure out how to do that in Stackoverflow. And I found out there were 2 solutions:
NSUserDefaults
SQLite database
In NSUserDefaults, when I want to store NSMutableArray, I must implement with NSKeyedArchiver to archive and unarchive array object, also do NSCoding protocol for each item in array object. But I can not do this solution because in each item, it has some fields from CorePlot library, so that I can not use NSCoding to these fields.
SQLite database, I can not use this solution because each item in array object is different class.
I would like to ask if any other solution to solve this problem?
I hope my words are clear enough to understand.
Thanks
I would suggest you figure out what kind of data is at the root of your CorePlot objects. If it is integers, then simply store them in NSUserDefaults, and then simply rebuild your NSMutableArray on re-opening the app. Another option is to store your items in a separate plist file.
Use this method to save:
- (NSArray *)applicationDataFromFile:(NSString *)fileName {
NSArray *paths = NSSearchPathForDirecotiresInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory
stringByAppendingPathComponent:fileName];
NSArray *myData = [NSArray arrayWithContentsOfFile:appFile];
return myData;
}
- (BOOL)saveToFileForStringArray:(NSMutableArray *)array
toFile:(NSString *)fileName {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
if (!documentsDirectory) {
NSLog(#"Documents directory not found!");
return NO;
}
NSString *appFile = [documentsDirectory
stringByAppendingPathComponent:fileName];
return ([array writeToFile:appFile atomically:YES]);
}
I am building an add-on to my app where the user can search for an item in a list that is pre-populated with data from a .plist file. It is an NSDictionary. If the term, the user searched for, does not exist, the user can tap a + button and add it so it is there the next time.
First of I thought it would be as easy as using the NSUserDefaults, but a few problems arises.
To have the list included I must place it in the bundle, but if it is there I can not add new key/value pairs to it. This I can only do with files situated in the Documents folder.
So I guess I have to bundle the plist, then on first run I'll move it to the documents folder and access it there.
This opens up the problem when I need to update the app, I guess it will overwrite the values the user put in.
Is there a secure, easy-understandable, right way to achieve the functionality I describe?
Thanks for any help given:)
Edit: **** the actual approach, as suggested by TheSquad and TomH *****
+ (NSMutableDictionary*) genericProducts {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [documentPaths objectAtIndex:0];
NSString *documentPlistPath = [documentsDirectory stringByAppendingPathComponent:#"GenericProducts.plist"];
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
NSString *bundlePlistPath = [bundlePath stringByAppendingPathComponent:#"GenericProducts.plist"];
if([fileManager fileExistsAtPath:documentPlistPath]){
NSMutableDictionary *documentDict = [NSMutableDictionary dictionaryWithContentsOfFile:documentPlistPath];
return documentDict;
} else {
NSError *error;
BOOL success = [fileManager copyItemAtPath:bundlePlistPath toPath:documentPlistPath error:&error];
if (success) {
NSMutableDictionary *newlySavedDict = [NSMutableDictionary dictionaryWithContentsOfFile:documentPlistPath];
return newlySavedDict;
}
return nil;
}
}
And for adding a new product to the list:
+ (void) addItemToGenericProducts:(NSString*) newProduct {
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [documentPaths objectAtIndex:0];
NSString *documentPlistPath = [documentsDirectory stringByAppendingPathComponent:#"GenericProducts.plist"];
NSMutableDictionary *documentDict = [NSMutableDictionary dictionaryWithContentsOfFile:documentPlistPath];
[documentDict setObject:newProduct forKey:[MD5Checksum cheksum:newProduct]];
[documentDict writeToFile:documentPlistPath atomically:YES];
}
I had the same thoughts with my sqlite database...
I end up doing exactly that, copy the bundled file into documents in order to be able to modify it.
What I have done is checking at each startup if the file exist, if it does not, copy it.
If you do an update of your App, the documents folder will not be touch, this means the copied file from the previous version will still be present.
The only issue is that if you want your plist to be upgraded you will have to handle that in your application. If you have to do so I suggest you use the NSUserDefault to check if a previous version of the app existed before...
The contents of the documents directory is not altered when an application is updated.
The contents of the documents directory are deleted when the user deletes the app.
When the app is run the first time write a flag to NSUserDefaults. On subsequent runs of the app, check for existence of the flag. (alternatively, you can just check for existence of the plist in he documents directory)