I'm making a catalog where the cells in my collection view will be either an image with a label or a pdf. There will be many collections and they themselves will be static. I want the user to be able to save the cells he likes and view them in his own custom view.
1) I could to store the image as data in Core Data.
2) I could just include the image in my App Bundle and load the image from there every time my app starts.
I've got it into to my head that reading data from a Core Data Store would give me more options when building my app as well as offer some boost in performance as opposed to reading it from the app bundle. Is that true? Keeping in mind of course that most of the data is static.
It seems inefficient to have images both serialized images in my app bundle and the pure data as well.
I think I'd rather have it all in the store but they have to be loaded from the bundle at some point in code right?
I'd love to know how other developers do it.
Now in Core Data there is an "allows external storage" option for binary data, which basically means if your file is bigger than 1 MB it will be stored automatically outside of your database, and you have to do nothing differently. In my opinion that's the way to get the best of both worlds, increased performance + automatization + fast queries (although they are slower than usual when you allow external storage, but still faster than doing it yourself)
Related
My app is a mood diary and to save data I've chosen to use Core Data (for strings, images, etc.); to allow the user to restore his diary I've implemented iCloud, that works well with Core Data.
Everything works well if I have not much entries, but when the images saved are too much the app is slow to load data and encounters memory warnings.
To save my images I've chosen Transformable data type and not Binary Data; I know that is not the best way to save images (saving url is surely better), but I need to sync my data on iCloud, and saving images as Transformable allows me to sync data in a simple way (thanks to the possibility offered by Apple Api to link Core Data and iCloud).
What can I do to avoid this memory warnings and sync my app pics on iCloud?
I've considered the possibility to save my pics on a custom photo album (if iCloud is activated for Photo app my app pics would be synchronized), but I need to save them with custom name to retrieve them from camera roll to my app, and for the moment I don't find any solution to save pic with custom name in a custom photo album.
Saving photos in document directory (and saving urls in my core data entity) would be the right choice for local database, but my app pics would not be synchronized.
There are a few things you can try.
First, add an image thumbnail property which stores a smaller version of the image. Use that whenever possible. Loading a bunch of full-size photos needs a lot of memory, so change to loading smaller images whenever your UI allows smaller sizes.
Beyond that you can change how you handle images using one of the following strategies. In ascending order of complexity (and effectiveness):
Make sure "Allows external storage" is enabled for the image property in your data model. This will let Core Data put the images outside the persistent store without requiring you to manage those files. This will save on memory if, for example, you sometimes fetch data but aren't using the image property.
Change the data model so that the image is saved in a different entity, with a relationship linking it to your current entity. This should make it easier to avoid "accidentally" loading images when you're not using them.
Put the images in separate files and keep only the file names in Core Data. You can still sync the images via iCloud, because you can sync files directly via iCloud outside of Core Data. But you'll need extra code to manage uploading/downloading the images. You'll also need to make sure you can handle the case where Core Data has finished syncing but the image is not available yet.
On this list, #1 is easiest but will probably have the least effect. Using #3 should be very effective but will require the most work.
I am fetching images from my server and need to store them on the disk. I was wondering what is the best way to cache these images to prevent excessive requests and traffic. From doing some research it seems that there are many options available but I am not sure which to use.
Core Data
Store in the Cache Resources Folder in the file directory
After storing these is it best to use a NSCache class to put these data into memory for quick access or is Core Data quick enough?
Based on my experience, you could use SDWebImage, which caches the images you request based on their url, so the next time you "request" it, it will check if it is in cache, if so it won't make the request and it will load it from it instead.
I'm not sure why would you need to store the image, maybe you could tell us the reason and see if we can help any further.
I've had great results using FastImageCache by Path.
What Fast Image Cache Does
Stores images of similar sizes and styles together
Persists image data to disk
Returns images to the user significantly faster than traditional methods
Automatically manages cache expiry based on recency of usage
Utilizes a model-based approach for storing and retrieving images
Allows images to be processed on a per-model basis before being stored into the cache
So this is more of a conceptual architecture question. I'm making a messaging app in iOS. Devices can send image messages. I am saving custom Message objects (which include images) to disk using NSCoder protocol. I want to remove the messages from memory when I don't need them (i.e. when the user logs out and disappears from users list view). I am appropriately encoding that user's messages to disk, and loading them when the user re-appears. However, on the messaging view (a dynamic UITableView where each cell displays the message content), the image content of the messages are cached within the UIImageView subview.
So, I am essentially creating duplicates of the images when I load the messages from disk. Every time a user logs out and then in (i.e. disappearing and then reappearing), the associated messages are saved and then loaded from disk (recreated objects), and my memory usage creeps upward once I go to the private message view and scroll all the way up in order to display all messages.
Ultimately, I want to clean the cache of message images so that I can free up memory when a user is no longer around. I have a good reason for saving messages locally; my question is: what is the best design for saving messages/images to disk, removing them from cache memory, then reloading them when I need to populate a dynamic UITableView?
I'd advice you to use some ready caching library like: SDWebImage, FastImageCache or Haneke. All of them are both using disc and memory cache, what will improve the speed of your tableView and decrease number of download requests.
You can of course make your custom solution, but it won't work as well as something written during months and tested via many developers. However if you want to, I'd suggest to take a look into one of these libraries and start by considering what they've done to make everything 'speedy'.
This way you just save URL in your Message instead of full image. These libraries will check URL, understand that they already have the image in memory cache and load it. You don't have to store it in your array of objects nor download again or save by yourself on disc.
Keeping your message objects on the disc seems weird, as this is slow - better to use database - CoreData/Mantle/FBDB etc, however that's your decision :) Also storing on the disc makes your Messages very easy to reverse engineering attacks and isn't safe.
So my iOS app has just been rejected because it's storing too much non-user-created data in the SQLite database, which lives in the Documents folder.
The app basically involves a relatively large library of images -- around 60-or-so megabytes of them to start, and there are also in-app purchases which each add an additional 60-or-so mb of images. Furthermore, the user can add their own images to the library.
Right now everything (images and all) is stored in an SQLite database, which is generated when the app is first launched. As the user adds more images, or purchases image packs, those images are added to the database. To the user, all the images (user-generated or not) behave the same in the app.
But Apple won't allow this: I can't have all that data stored in the SQLite database in the Documents folder unless I set it specifically NOT to back up to iCloud, as it's all recreatable data.
But if I set it to not back up, then the user-generated data won't back up either, which I definitely don't want.
Any suggestions how I might "split up" the database, such that all the user-generated stuff can be backed up, but the included-or-purchased stuff isn't?
The reason you are being rejected is not following the Data Storage Guidelines. Data created or edited by the user belongs within NSDocumentsDirectory, while application data should be stored elsewhere (i.e., the Application Support directory). These requirements are a result of how iCloud backup and disk space purging work on iOS.
For a Core Data application, this means your persistent stores must be split into two different sets of files, in two different locations. This, in turn, ends up driving much of the application architecture and data model. To have relationships between the user data and application data, for instance, you must use two different managed object model configurations and the relationship must be a fetched property.
There is more detail on how to implement this in this answer.
An alternative for your specific case would be to save the images on the file system, in the caches directory or elsewhere. User images could exist in NSDocumentsDirectory while application images could exist in NSCachesDirectory. This would remove the images from Core Data and instead your model objects would have the path to the image on the file system. This would be a short term fix to get you through submission, and would probably work.
One option will be, storing your data to a server and calling is using web service. During first launch. Or as per requirement.
My situation:
I have an app that needs to store 10,000 - 30,000 locations in some sort of storage method, which are then displayed on a MKMapView as individual pins. I also have a server that needs to be able to add to the database through pushing out changes.
Through grouping pins I've eliminated all issues with the MKMapView, my biggest focus is now on speed, storage and being able to add and replace the storage contents. What I'm currently doing is I have a text file of currently 1,000 locations as JSON-formatted, then they're just read as an array and sent to my custom map view (no issues there). My only issue is how I could update that text file (rather than downloading massive amounts of data), and store almost 30,000 locations.
Is this even feasible? It seems my current setup could scale pretty much perfectly, it's just this updating system that is causing me a headache.
Your current setup won't scale forever because you have to load the entire file into memory in one chunk. Eventually it will get to large to manage and will eat up to much memory. Unable to purge memory in the event of system low-memory, the system will shut your app down i.e. it won't be able to stay in the background but will have to reboot each time the user switches back to it.
To update, you will have to load in the entire file, parse the JSON, figure out how to update the resulting data structure, then write it all to file. One error anywhere in the process could corrupt the entire file.
You really need to look at using Core Data or even SQL. Core Data has a learning curve but once you master it, it makes implementing designs like your app trivial. You also get automatic scaling and efficient memory management.