Is there any difference between writing an objects(ex array types and NSObject types) to plist and NSFileManager.
if so can i write 1000's of images data and mp3 songs to plist.
As a plist file is an XML (mostly text) file you must archive your data before writing and unarchive after reading (see NSKeyedArchiver here).
NSFileManager, however is a wrapper around generic filesystem operations and there is no need to marshall the data into text in order to store it. The stored data will therefore be much smaller, much quicker to read/write and is the obvious choice.
NSFileManager is used to do things like copy a file, remove a file, and move a file. You wouldn't use NSFileManager to write out a new file. It's only good for working with existing files. It isn't comparable to a plist in the sense of using a plist vs. NSFileManager.
However, if the question you're trying to answer is should I store all my data in a plist or in separate files then that depends. If you're going to store 1000s of images and mp3s, then you definitely do not want to store them all in a single plist. Plists are an inefficient format for storing and updating large amounts of information, both in terms of speed and memory. For example, if you wanted to update a single string in your plist, you have to read the entire plist into memory, update it, and then write the entire plist back to disk. You cannot update just a portion of the plist using the standard plist functions provided by Foundation. If your plist contains all your image and mp3 data, it's going to be really slow.
You may be able to get away with using a plist as a manifest for your images and mp3s which are stored as separate files on disk, but even that can get slow. I'd recommend using SQLite or Core Data instead for the manifest of files and then keeping each image and mp3 as a separate file in the file system. Or, if you don't need to store any metadata with each item, you don't need the manifest at all. If you do end up going with a plist for your manifest, make sure to save the plist as a binary plist using the NSPropertyListBinaryFormat_v1_0 option. This will make the plist take up less space on disk and de-serialize faster when you read it again.
Related
This is a bit of a two part question, for working with 40mb xml files.
• What’s a reasonable size to store in memory for a program running continually in the background?
• How to find what has changed in an XML file.
So on the first read the XML is loaded into NSData, then uploaded to the server.
Now instead of uploading a 40mb XML every time it changes, I would prefer to upload a “delta” file containing only what has changed. The program would monitor the file for change, and activate when it’s been modified. From what I can see, I would need to parse an old version of the xml file and parse the modified xml file, then compare them? Is it unreasonable to store 80mb in memory like this every time the file is modified?. Now I’m assuming that this has to be done with a DOM parser because I can’t see how you could compare two files like that with a SAX parser since it only has part of the file stored?
I'm a newbie at this so any help would be appreciated!
To compare two files:
There are many ways to do, (As file is to be considered, I may not be correct):
sdiff file1.xml file2.xml A unix command
You can use this command with apple script.
-[NSFileManager contentsEqualAtPath:andPath:]
This method checks to see if two files at given path are the same file, then compares their size, and finally compares their contents.
For other part:
What size is considered for background process, I dont think so, for an application it matters. You can save these into temporary files. Even safari uses 130+ MB as you can easily check through Activity monitor.
NSXMLParser ended up being the most useful for this
I want to be able to put a file to a variable so I can interact with it. For example I could put a wav file into a variable and play it back without having to distribute the separate file. Is this possible for instance by using Base64. I have seen some Python programs for example that have images embedded in the code.
Yes, you could conceivably store the contents of a binary .wav file as a static, uuencoded text array.
Probably a better way to go about it would be to create a "resource" for your binary data:
http://msdn.microsoft.com/en-us/library/xbx3z216.aspx
I have been working with base64 encoding. I have successfully encoded images to NSString from NSData, I have also decoded it back to NSData.
So right now I want to store images in Core Data. But would it be best to store an NSString, NSData or the third transformable?
The reason I convert images to NSString is because I want to store it in XML too.
Thanks in advance.
Transformable (as per #timthetoolman) is the easiest way. If your images are large, though, as of iOS 5, the right way to do this is to use the "Binary Data" attribute type and choose "Allows External Storage" so that Core Data can store the large blob of data outside of the database. This can be much more efficient.
Use an NSValueTransformer to convert from your image to an NSData object and then store the data blob in Core Data. You can register your value transformer subclass in the modeling tool. You can check out Apple's PhotoLocations example or this tutorial shows how.
Edit for completeness: as others have pointed out too large a data blob will cause performance issues. As pointed out by #Jesse, iOS5 has an optimization where if the data blob is too large, then Core Data will store it outside of the persistent store. If you have to target pre-iOS5 and the image is too large then you should save the file somewhere in the sandbox and store the URL in the Core Data store. A good discussion in the Apple Dev Forums is here and discusses the limits of storing data blobs in Core Data.
Good Luck
I don't think you should store them in core data, I tried that with images once and found it to be too slow. You should store the locations of the images in core data but just write the images to a file. You can do that as follows:
// JPEG
[UIImageJPEGRepresentation(image, 1.0) writeToFile:jpgPath atomically:YES];
// PNG
[UIImagePNGRepresentation(image) writeToFile:pngPath atomically:YES];
Target iOS5 or later -- Performant Image storage becomes trivial
Newer versions of Xcode and iOS now make storing images both easy and performant. You no longer have to choose to store your images in core data for convenience or in the file system for performance -- Core Data will take care of it for you.
UIImage now conforms to NSCoding in iOS 5. If you're able to target iOS 5 and later, you can just set the the managed object's attribute as Transformable and be done.
if you check the "Allows External Storage" option, Core Data will make the decision whether to store the BLOB in the managed object or as an external file -- all transparently to the developer. to cause larger images to be saved outside of your Core Data store
I've developing a Cocoa app that has certain resources (images) which I wish to protect, but still display. Normally one would just place these in the resources folder, but storing there makes it quite easy to grab and use. Is there any way to keep these images hidden, but still access them within the app?
Simple solution:
Merge all files into one big data-file, optionally using 'salts'.
Then retrieve specific files with something like this:
NSData *dataFile = [NSData dataWithContentsOfFile:filePath];
NSData *theFile = [dataFile subdataWithRange: NSMakeRange(startPos,endPos)];
This does not really protect the files,
but prevents people simply dragging out the resources.
At least, the data-file is unusable, certainly with salts.
Another solution:
Create NSData object for every resource.
Add all objects to a NSMutableArray.
Convert the array to one big NSData object.
Write the NSData object to a file.
And add it to the resources folder.
Your app can then read the data-file.
And retrieve the array with the resources.
// Convert array to data
NSData* data=[NSKeyedArchiver archivedDataWithRootObject:theArray];
Use NSKeyedUnarchiver to retrieve the array again.
In order for you to protect the images in one big file, you can just dump the image data to a NSData object sequentially.
If you want, you can use either salts, as previously mentioned, or you can use AES encryption method, as shown here.
Then, you will have to either save the image files structurally (using an NSArray or similar) or record the image offsets so you can retrieve the image data blocks correctly.
This has some drawbacks, specially if your images change over time. That way you will have to monitor those changes and re-structure the file accordingly.
On other option is for you to simply mask the image files by changing name/extension to one of your choice. This will leave some users away from touch.
Finally, you can search for some archiving frameworks using zip like functions and keep the images there (as Blizzard uses in their MPQ format). This will be the best option (since it provides you with encryption methods and it abstracts you of the mechanisms of encryption and archiving) but it may not be easy to find such a framework.
Why do you want to protect the images? It goes without saying that anything you display can be recorded with a screenshot, so if you're trying to protect the images from the person viewing them, there isn't much point.
If you still want to protect them (say, some images should only be available to certain people), encrypting them on disk might be an option. I'm not an Objective-C guy, but this1 seems like a good place to look.
I have to save some 100 sentences in my app. Each sentence is around 50-90 characters. I can create a .plist file for this. But i dont want to read the whole .plist file, just want to read a specific index. Is it possible?
There's no API for reading plist files partially. For 10kB files that's not much of a problem, just read it and discard what you don't need.
I am not sure whether it's possible to avoid reading whole file. But if you want to access a single entry then you can create an array from plist and access the index (i assume that you are already aware of this). It won't take much memory unless your app is already heavy loaded.