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.
Related
I am able getting data from server and display on UITableView, It's working fine. But when I go to another tab and return to same tab it will call to server for data. I want to store data locally once get from server.
Please suggest me your thoughts.
Thanks!
You have to store the file on the device and this is possible in a few ways:
Store the files in the App its Documents directory
Store the files in the App its Library/Caches folder
Store the files in the App its Library/ folder
There are a few considerations for each option:
Files stored in the Documents folder are by default backed up by iCloud. You really have to think if this is necessary because you're eating up iCloud storage space from the user (for which he/she may pay).
Storing files in the Caches folder is a good way, but they may be deleted by iOS if the users disk is running low on space (therefore the name Cache).
Storing files in another (manually created) folder on the device will keep them as long as the app is installed. No iCloud backup or no removal by iOS
Getting the location of the specific folder can be done using:
[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
Where you have to replace NSDocumentDirectory by NSLibraryDirectory when you want the NSURL to the Library folder.
Storing data is as easy as creating an NSURL which points to the location where you want to store the data and then call the writeToURL:atomically: method on the NSData you want to store.
Converting UIImages to NSData can be done using UIImageJPEGRepresentation or UIImagePNGRepresentation.
i would prefer to use the HJCache library for the temporally store images.
For that followings are the reasons to implement the HJCache open source library.
Make it easy to use asynchronously loaded images in iOS apps.
Make it easy to use a shared file cache.
Make memory management ‘just work’ according to Cocoa norms.
Support typical cases of viewing images, eg scrolling through a list of tweets showing the tweeters profile pic, swiping through a photo album loaded over the net.
Allow the library to be used for other kinds of data too.
For more detail and tutorial visit the github and author blog
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'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 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 :)