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.
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 am downloading some mp3 files through my application using NSURLConnection. Actually where can I save the downloaded file. Someone says that saving in to NSDocumentDirectory will lead to app rejection.
Can I save the file to NSCacheDictionary and retrieve this from itunes?
I used this bit of code to save files to NSCacheDictionary
NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(
NSCachesDirectory, NSUserDomainMask, YES)
objectAtIndex: 0];
NSString *documentsDirectoryPath = [cachesPath stringByAppendingPathComponent:#"music.mp3"];
[receivedData writeToFile:documentsDirectoryPath atomically:YES];
Can I use like this?
If you save the files to NSCacheDictionary you will not be able to retrieve them from itunes.
Edit:
You can store the mp3 files to NSDocumentDirectory and set "do not backup" flag
for setting the flag you can check the Technical Q&A QA1719.
For additional information you can check the docs.
specifically:
Use this attribute with data that can be recreated but needs to
persist even in low storage situations for proper functioning of your
app or because customers expect it to be available during offline use.
This attribute works on marked files regardless of what directory they
are in, including the Documents directory.
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 display text and images in a UIWebView. Content isn't always the same. I access images within the content using the bundle path. For an inbetween versions update of content, I'd like to allows users the ability to download new content (text & images). This new content will also display in a UIWebView. The problem is I will have to use a disk path rather than my common pattern of using the bundle path. Unless there is a way to repackage the image at runtime into the bundle.
Once the next app store update for the app is availble, all of the previously downloaded images will be in the app bundle. On this update, I'll write overwrite the previous content and use the bundle path for images. Content will be exactly the same minus the image path.
Can anyone give some insight into how this might work or a better approach?
So far as I know you cannot repackage the bundles on the iPhone once your app has been released to the App Store. So go the other way, and put the data from the bundle on the filesystem so you can change it at runtime.
My usual technique for this stuff is:
bundle up the initial data
have a routine that checks for the presence of a versioned file on the iPhone's filesystem at startup
if that routine doesn't find the current version of the file, copy all the data into the iPhone's filesystem
reference the data from the filesystem in my app, rather than using the bundle path
So, essentially your bundle is just a delivery mechanism, a way to preload the filesystem with the stuff you are going to need. Once it's on the filesystem you can change anything you wish.
Agree with Benjamin - you cannot change your bundle contents.
Instead you can (and should) save your downloaded contents to Documents folder of your application sandbox. You can get the path to it this way:
// Look in Documents for an existing plist file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
Moreover contents of this folder persists during updates so it may be not necessary to put downloadable optional contents to the application bundle.
I have an iPhone application in which a number of domain objects are populated with user-entered data. In order to restore state after being interrupted, these objects implement the NSCoding protocol and are written to disk (the Documents directory) in the applicationWillTerminate message. Then, when the application is launched again, the bytes of data are loaded up and the domain objects are repopulated. Code to get the documents directory is as follows:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
This worked great in the simulator but once I deployed the app to the iPhone it stopped working. The reason why is iPhone error code 513 - which apparently means "permission denied." There is a note in the iPhone dev docs that explain a little bit more -
On the device, the returned path
(documentsDirectory) is similar to the
following:
/var/mobile/Applications/30B51836-D2DD-43AA-BCB4-9D4DADFED6A2/Documents
However, on the Simulator, the
returned path takes the following
form:
/Volumes/Stuff/Users/johnDoe/Library/Application
Support/iPhone
Simulator/User/Applications/118086A0-FAAF-4CD4-9A0F-CD5E8D287270/Documents
This is the exact behavior that I'm seeing. I'm not really sure how this relates to getting a permission denied error and what I can do to fix it. It does say below -
To read and write user preferences,
use the NSUserDefaults class or the
CFPreferences API. These interfaces
eliminate the need for you to
construct a path to the
Library/Preferences/ directory and
read and write preference files
directly. For more information on
using these interfaces, see “Adding
the Settings Bundle.”
If your application contains sound,
image, or other resources in the
application bundle, you should use the
NSBundle class or CFBundle opaque type
to load those resources. Bundles have
an inherent knowledge of where
resources live inside the application.
In addition, bundles are aware of the
user’s language preferences and are
able to choose localized resources
over default resources automatically.
For more information on bundles, see
“The Application Bundle.”
I don't see how I can use the Application Bundle to load bytes of data though. Any help or examples?
Not sure how this works, but apparently using stringByAppendingPathComponent instead of stringByAppendingString for path creation fixed the problem.
The paragraph related to the application bundle refers to:
NSString *path = [[NSBundle mainBundle] pathForResource:#"somefile" ofType:#"png"];
This and other methods from NSBundle allow you to refer resources from inside the application bundle without actually knowing where the application bundle is located.
Disclaimer: I haven't worked with the iPhone.
With the disclaimer in mind, in plain OS X it's considered bad form to write stuff inside the application bundle. You save stuff under the user's Application Support directory -> see NSApplicationSupportDirectory.
I got this error (513) because the path was wrong. Double checking my path fixed the problem :)