I am trying to save drafts using NSUserDefaults but I am not sure if it is the right place to save data not user's preferences in.
My application allows user to choose 1 or 2 images to upload and share. Users can save draft and come back to upload later. My current approach is to save the chosen UIImage to /Library directory and save the file path to NSUserDefaults.
The data structure is NSUserDefaults -> Draft NSDictionary -> key - NSArray. I have many drafts (just like email drafts). The Draft Dictionary contains a saved date string as a key and string file paths in NSArray. The saving process doesn't have any problems currently. But because in NSUserDefaults doc, they say:
The defaults system allows an
application to customize its behavior
to match a user’s preferences.to match a user’s preferences.
So, I don't know if my approach is good or not, any possible future problems with it?
Do you suggest me any simple solution that can do this well without having to code much. I know there is CoreData but I don't know much about it. Is it easy to learn and implement?
I don't know if this can affect some memory problem or not, but I expect that a user may save drafts less than 100.
You don't want to save any actual data to NSUserDefaults, however, it acceptable to save the previous application state in the defaults such that the app can resume where it left off.
Your data structure seems overly complex. You can just save an array of file paths directly to the user defaults.
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
NSArray *draftPaths=[NSArray arrayWithObjects:filePath1, filePath2,nil];
[defaults setObject:draftPaths forKey:#"DraftPaths_Key"];
// to retrieve
NSArray *previousDraftPaths=[defaults objectForKey:#"DraftPaths_Key"];
You don't want to save the files into the cache folders because the system can delete caches if space gets tight. Instead, save them to custom folder in the /Library directory. You can get the path to the library with:
NSArray *libraryPaths=NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *libPath=[libraryPaths objectAtIndex:0];
Related
I am making a note-taking app but this app won't be a traditional note-taking application. This application will be used by my company's employees and engineer teams in my company.
The notes content will be large because contain some mathematical expressions. Also, files must be sent to dropbox as text and pdf files.
I wonder which is the best method of these for storing large data content:
1- Simply writing notes content to file (like note1.txt) in Documents directory
I am using this function for writing files:
-(IBAction)writeFile:(id)sender
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fileNameData=[NSString stringWithFormat:#"%#.txt",fileName.text];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:fileNameData];
NSString *str = fileContent.text;
[str writeToFile:filePath atomically:TRUE encoding:NSUTF8StringEncoding error:NULL];
}
2- Or storing file contents in database and create a file when user wants to send the note to dropbox and send this created file to dropbox?
I have created note-taking apps before but in this one, files will be large and I am worried about performance.
UPDATE
I did some trials. I tried to write and read the same string using both technique; core data and files.
It takes about 16 seconds to read string from Core Data and about 5 seconds to read from the file with stringWithContentsOfFile method.
I know that is not very accurate results but I guess Core Data is not very proper for me.
If I am wrong, please correct me.
Well this should be done using core data Core Data Usage and for the benefits please read this SO question Why should I use Core Data for my iPhone app?
I made a Notes App myself and used core data and it works fine . Hope this helps.
EDIT :
Or check this link Relating to the Data Storage guidelines. It includes all types of guidelines as given by Apple.
Core data is a pain the in butt to get setup and working. Do you have a incredibly large data set or need to do entity relationship between the files?
If not I would just have a dictionary or array that contains a simple object that has meta data about the file (last access time, title, file location, etc) I would then load this dictionary and use it in a table view for selecting the files.
The files themselves can be loose files on disk in the data directory. To improve the performance of saving just copy the string and then just write it out asynchronously using GCD. When a user selects one file to open again load it using GCD and show a small progress bar. if these files are small it will be close to instant for loading.
CoreData would be quicker than read/write to files. But, you are not worried about performnace when you write to file. You are worried about Performance when you send the files to dropbox How frequent is that? If that is done not so frequently like once a day , then may be text files is a better option than coredata or sqlite.
I'm trying to implement a backup of my application's data and user preferences (stored in NSUserDefaults) as email attachments with option to restore them at a later date.
I've got the process working fine for my application data file simply by attaching the contents of the file to the email, but can't work out how to do the equivalent for the user preferences. The Root.plist in the Settings bundle contains only the template for the settings interface and none of the current settings.
Reading the settings into my own plist and saving that to the documents directory is an option but seems inelegant and overly complicated. Is there a better way?
I wouldn't go looking for the plist that stores NSUserDefaults, because it's not directly exposed by the API, and hence is an implementation detail that could be changed at any time.
Instead,
[[NSUserDefaults standardUserDefaults] dictionaryRepresentation]
will give you an NSDictionary containing all the key-value pairs that your app has stored.
See this tutorial,
http://iphonebyradix.blogspot.in/2011/03/read-and-write-data-from-plist-file.html
To read user defaults , use this method
-(id)getFromNSUserDefaults:(NSString*)pForKey
{
id pReturnObject;
NSUserDefaults *defaults =[NSUserDefaults standardUserDefaults];
pReturnObject = [defaults valueForKey:pForKey];
return pReturnObject;
}
Reading the settings into my own plist and saving that to the documents directory is an option but seems inelegant and overly complicated. Is there a better way?
Given that there is no official API (that I know of) that directly supports what you want, I find it quite elegant and not very complicated to write a few lines of code that create your own .plist file. See yuji's answer for a starting point: Just one line and you already have a dictionary with all the settings that you want. How much more elegant can it get? :-)
It may not be the answer you would have liked to hear, but my advice is: Don't try to fight the system, you usually lose in the long run.
What is the correct/best way to store files on the iphone?
I would like to save a file in some directory on the iphone. I have read that filing the users home directory isnt good practice.
Where should the files be stored and how can an URL for these files be saved as well? So that after saving a number of files to the users phone, the urls can be stored so that the files can be managed at a later stage.
I would like to store files, keep a handle to the file and store these handles in a data structure as well as retrieve the files later using URLs in the data structure so that the files can be accessed and deleted.
What would be the correct/optimal way to do this?
Files are stored in Documents folder of the App.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
[paths lastObject];
will get you the Document path.
I would then use NSKeyedArchiver and NSKeyedUnarchiver to store the URLS, and also put that into the Documents.
To see what's in the Documents Directory just use NSFileManager contentsOfDirectoryAtPath:error: method, which returns a handy NSArray. Call lastObject and there you go.
Update:
NSURL must be encoded and decoded with NSKeyedArchiver and NSKeyedUnarchiver, as they are not a basic object of plists. Although you could could convert them to strings, which are, then you could use [array writeToFile:file atomically:YES]. The other option is CoreData but that might be a bit much.
It would be best to store all URLs in one file and just overwrite and with changes when urls are being removed and added.
You are not filling the user's Document directory, you are filling the app's document directory. The documents folder is where you but files that the user has generated. In the future you may decide to open up the Document directory to iTunes so the user can add and remove files that way. Things that just relate the app should be stored in the Library folder.
I hope this explains what the hell I was on about a little better. I seemed to got the impression that you wanted to just store URLs as individual files and store the handles. You could get the handles but just knowing the directory you stored everything in. Get an array of the files in that folder and just load them up by using an unarchiver or initWithFileContents: from NSDictionary or NSArray.
i'd like to have the user tap a cell in the tableview and hear audio. the information for the cell is loaded from core data, so i'm assuming i put the path to the audio file in core data as an attribute with type 'string'.
i am completely lost as to where to go from here. how do i call the path? after a lengthy search, i haven't found much on the topic so any help is greatly appreciated.
You should store just the file name in the managed object and then reconstruct the file path each time.
In iOS the name of the app's directory is just a UUID and it is different on every install. Further, the system may change the directories UUID without warning. This is part of the security system.
Suppose you wanted to put the audio files in a directory called AudioFiles in the Library directory. You would do something like this:
NSString *fileName=//... file name from the managed object
NSArray *libraryPaths=NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *libPath=[libraryPaths objectAtIndex:0];
NSArray *components=[NSArray arrayWithObjects:libPath,#"AudioFiles",fileName,nil];
NSString *theAudioFilePath=[NSString pathWithComponents:components];
See Low-Level File Management Programming Topics:Standard System Directories
Depending on how you play the audio files, you may need to convert the file path to a file URL.
Your question is quite wide. The best way for you to get started is to work through Apple's avTouch example. It will show you how to load and play audio files.
I have tried the various techniques described to serialize a plist I need in order to save the favorites of the user.
Some people also say it is better to save that data into the "user defaults" file.
Which is the better technique and how are they serialized. I have this code
[plistArray writeToFile:filepath atomically: YES];
which adds the object to the array, but cant seem to save the plist edits.
Regards
If you want to save preferences, then the appropriate method is to use the NSUserDefaults mechanism as it will save you a hell of a lot of time and hassle.
However, if you're using a PLIST as a means of persisting data that's stored in say, an NSDictionary, then I think it would be appropriate to use the writeToFile approach.
If you want to save preferences of any kind, just store them in the user defaults dictionary. That's the only correct way – and additionally you make sure, that iTunes will back it up, if the user syncs its phone.