So i have this situation with images. In one of app stages i get all user photos from his photo library. I get them as ALAsset's. I let him choose photo he wants. Then i save his chosen photo to applications directory as full size photo with HIGH_ prefix and a thumbnail of a photo with LOW_ prefix. I need this because photos have some properties like time etc. I save those properties to SQL database with a field of photo name that begins with HIGH_ or LOW_. When i need to get photos i get properties from db and then do [UIImage imageWithContentsOfFile:photoPath]. Can someone tell me how to do it more efficient because writing and getting photos like this takes some time. And on iPhone 4 i sometimes even get memory warnings. AND another question would be, how should i save photos fetched from web?
I stand corrected, instead of using core data, Apple writes,
It is better, however, if you are able to store BLOBs as resources on the filesystem, and to maintain links (such as URLs or paths) to those resources. You can then load a BLOB as and when necessary.
So you are doing it correctly, but maybe you should check out transformables. Just make sure you remove images you aren't using from memory if you are getting warnings
From documentation: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/Articles/cdPerformance.html
Under the section 'Large Data Objects (BLOBs)"
Another way to do it with a transformable:
Which way to store data(image)? NSData, String or Transformable
In fact, perhaps transformables are for core data at least:
How should I store UIImages within my Core Data database?
Related
I am planning to use Core Data in my app If there is no internet connection.
So what i am doing is retrieving images and videos from my server. I currently download them (Images for example) from the url retrieved from the server and convert it to UIImage NSData and then populate my tableView.
Now to the CoreData:
Some may say storing files in coreData is a bad idea, But as I shall only store a maxium of 5 images/videos at once I don't thing storage or speed shall be a problem as they will not be enourmous files.
To the question:
I have to save I guess the UIImage to CoreData, so obviously I need to get the URL then download the image and finally save it to coreData.
But If I do so in my query for getting the actual posts that would slow down the query possibly a couple of seconds, and I would prefer not to do so. So I was wondering what would be the best way?
I am downloading the images async with SDWebImage each time a cell appears, so If I save the images to coreData once they are downloaded that would mean to save 5 images to CoreData I would need to scroll 5 Cell's.
But I would prefer to: Load the app, download the Images/videos from server as normal and populate the tableView, and once all that has happened I would like the post's to already be saved to coreData.
So If I immediately close the app after the tableView gets populated then disconnect from the internet or go into AirPlane mode and re-open the app I have the posts in the tableView.
I know how to do most of the saving to coreData etc... But I would like some more proffessional advice and tips on how I should approach this.
What I would like to achieve?
1) Open the app
2) Download 5 images/video from the server (Up too here all good)
(From here on I would like some advice)
3) Empty the coreData if there was any previously images/videos saved
4) Save the last 5 images/videos I downloaded to CoreData.
What would be the best solution and quickest way to do so?
Thanks to anyone that can offer some advice.
Background
iOS devices, like most computers, have persistent storage. (e.g. a hard drive or an ssd)
To persist data across system shutdown events, etc., your app can save it directly to this store using the filesystem. This is a quick and simple way of storing data.
If you need a more structured approach, you could use a database. This approach allows you to work with your data in a more organized fashion (i.e. in rows and columns, with relationships, etc.) This database would be stored on the filesystem, but your app would work directly with the database file(s) itself.
On iOS, the typical database used is SQLite.
Core Data is another layer on top of one (or rarely, multiple) databases. This approach allows you to focus on your data as entities with relationships to each other. (e.g. User -> multiple Follower, etc.) Using Core Data, you can usually ignore the databases and the filesystem underlying it.
On iOS, Core Data is typically implemented with one SQLite database as a store.
Your Use Case
If all you need is to store a few images or videos to your device, then storing directly to the filesystem can work pretty well.
Assuming you already have your file in hand, you just need to:
1 – get a directory location
var documentDirectoryUrl: URL
do {
try documentDirectoryUrl = FileManager.default.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let imageUrl = documentDirectoryUrl.appendingPathComponent("imageFileName.jpg")
} catch {
// error handling
}
2 – write your file to disk
if (try? imageData.write(to: imageUrl)) == nil { // nil == false
print("Error: could not save image to file system.")
}
Reference
iOS File System
Core Data
SQLite on iOS Tutorial
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 want users to save the picked image and video within the app. So I wanted to know what is the best. Should i convert the picked images and videos to NSData and save in Core data? I search everywhere and everyone recommend to use Documents Folder to save images and videos because coredata is slower. I just started learning CoreData so I don't have much knowledge about it. Here is what I have come up.
Users pick the image or video -> App Saves it to documents folder -> Using coredata, application stores the filepath as string to access the image or video. (and User can backup anytime using icloud)
and Users can access those files in their other devices using iCloud. Please explain me if I'm incorrect or if you have better alternative or the question is wrong in any way. Thanks
I've done both ways and for me it's just a matter of how to use the database. If you'd like to to be able to backup the database and share with other, I would recommend storing files in CoreData as NSData. If it's just a local database it might be easier to store URL's to images stored on disk.
When you setup a Binery field in CoreData you can optionally select "Allows External Storage" which basically store the file on disk for you, but you can load it from the databas as if it was stored in the db. This is what I use most for images.
With this option, it is easy to create a zip file of the database and all binary files connected to it and also easy to unzip it to make a restore of the database.
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.
I am very new to core data and am trying to learn how to store large files, like images and short .mp3s. My app has about 300 different images and short .mp3s that are triggered to be displayed/played by user interaction, and as far as I can tell, I should use core data for storing these files.
I added a core data .xc file to my xcode project, and created an entity with attributes. I chose an attribute named "binary data" and checked the box "Allows External Storage," which from what I've read allows me to easily persistently sore files on 5.x or newer iOS phones. I know that I can program the app to get and set these attributes, but how do I just store my images and music files here?
Please help with me with code/understanding. It seems to me I should be able to somehow use the core data interface to set up a bunch of entities containing attributes of "binary data" that are my images and .mp3s, and whenever I need to display a pic or play a sound, I could call the entity and its attributes.
Thanks for the help!
I store compressed images (jpegs) with Core Data and it seems fast enough. But these are compressed to < 100K.
If you want to store items bigger than 100K, you might want to just save the file to "disk" doing something along the lines of Write a file on iOS
Then, save the file path to a string in Core Data. To load the file, get the file path from core data then read the file in.
I think Apple recommends the cutoff at 100K.