How can I make the way I add images to the core data more efficient?
Its a pretty bad idea to save "Data" or Image here in core data persistance. Also i think you are running this code in the background queue, if not then thats also a bad thing. But then again, saving the image or data into core data persistant store is a very bad idea and should be avoided whenever you can.
As an alternate you can do this -
Save the image in the local directory with a path and a unique
filename.
Save the filename in core data except the path.
Next time when you retrieve the image, get the filename from the Data store.
Append the filename with the whole path untill the folder. Retrieve the image.
This is a much more efficient and better way to store images.
Related
So I need to save pictures (made by the user) inside the app. I don't want to send them to a server and keep the link.
I am currently using Realm to save data, but I heard that it was not ideal to save images. What are the best practices for saving images locally?
(I will sometimes need to save hundreds of images.)
What kind of your data do you save ? ( link, data, image).
You should convert image to base64 then you save them into Realm. let write them in background task.
it will reduce volume and time to store them in Realm.
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 developing an app on xCode 5, iOS 7. I have some data stored in CoreData. My requirement is to upload that data to RackSpace. Whats the best way to do this?
Where can I find .sqlite file associated with CoreData?
The SQLite file is wherever you put it. There's no magic to it, you have to tell Core Data exactly where you want the file. You do this when you call addPersistentStoreWithType:configuration:URL:options:error:. The URL argument is the location of the SQLite file.
If you try and use the file directly, make sure that:
You shut down your Core Data stack completely before doing so, to make sure that all unsaved data has been flushed to disk. That means no managed objects, managed object contexts, or persistent store coordinators in memory anywhere.
Make sure to get the SQLite journal files. If your store file were named Foo.sqlite, they will be named Foo.sqlite-wal and Foo.sqlite-shm and will be located in the same directory. If you don't get these files, most or all of your data will be missing.
However simply uploading the file is not a good solution for syncing data. To sync data, you'd have to download a copy of the data, load that, and compare every object in the file with every object that's already on the phone. It's not impossible but it's definitely making things much more difficult than necessary. There are many options that can simplify the process, including full service providers like Parse, SDKs that let you use one of a variety of back ends like Ensembles.io, and others.
I have been developing an app with cloud/server data source. So naturally the process is one thing at a time. So at present, to fill my tables, I query the server which returns an array. The array contains urls to images and then from the urls I load the images using SDWebImage.
Now I am entering the stage of development where I need to implement Core Data for all the data in my tables (i.e. texts and images). So far I am considering the following approaches:
I can load the array from the server into core data (imagine properties as: firstName, lastName, photoUrl, shortBio) and then pass the photo url from core data to SDWebImage to display the image in the table cells. OR
I can load the array and the image into Core Data (i.e. load the array into core data in the background and then for each row, load the image into core data)
Of course the point here is that if I use SDWebImage it will save the image in its own caching system, which from my limited understanding may or may not be entirely consistent with what is in core data. On the other hand I don't understand core data enough to know if it handles saving images well in terms of performance (i.e. knows it's an image and therefore handle the file linking).
So What is the best way to do this? Can SDWebImage work in harmony with Core Data? Or is SDWebImage redundant since core data is good enough all by itself?
Another thing to note is that presently, my data loads from server immediately and then the images come as SDWebImage loads each into its UIImageView. This may not be a problem with Core Data since ideally the image will be in the local DB. Any thoughts?
Based on your question and comments, it seems you are trying to locally cache images that were retrieved through an HTTP request.
The URL loading system is already caching the images. There is no need to implement another layer of caching on top of that, wether it be SDWebImage or CoreData. When an HTTP response is received from the server, the server includes "freshness" information that informs the client how long and under what conditions that response is valid. The URL loading system, by default, obeys those rules. You can check the freshness information of responses using a tool like Charles or REDBot. The server is the only party in this conversation that can know how long a response is valid for.
The URL loading system does not, by default, cache to the filesytem - only in-memory. This is easy to change:
cache = [[NSURLCache alloc] initWithMemoryCapacity:(1024*1024*512) diskCapacity:(1024*1024*1024 * 100) diskPath:#"Cache.db"];
[NSURLCache setSharedURLCache:cache];
Or when using NSURLSession:
cache = [[NSURLCache alloc] initWithMemoryCapacity:(1024*1024*512) diskCapacity:(1024*1024*1024 * 100) diskPath:#"Cache.db"];
[sessionConfiguration setURLCache:cache];
session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
Storing image data in Core Data is something in general to be avoided, at least with the NSSQLiteStoreType persistent store. Even small images are large in the SQLite database and cause fragmentation, etc. that impact performance. If you are going to store image data in Core Data, it's preferable to use external storage - either by use Core Data's own external records storage, or by storing image data on the filesystem and referencing it in managed objects by using URLs.
However, if you are using Core Data OR SDWebImage to "cache" images, you are ignoring the freshness information that was returned in the server's response unless you implement your own validation layer - which the URL loading system is already doing for you!
Regardless of the question semantics, I think you need some more hard information to inform your decision.
It would be useful for you to know that storing large images (larger than, say, thumbnails) is not recommended and will lead to performance issues. Core Data has an option for large data where you can check "Store in External Record File". Alternatively, you can administer your own cache data (in this way you can flexibly update the images via download on a per-need basis on each device sharing the same data). The accepted best practice is to only store the image URL in Core Data (typically relative to the application directory) and handle the file storage / display separately.
I do not know SDWebImage, but this might provide some of the functionality that you need in the light of the above.
I hope this helps you make your decision about the data architecture.
I have an Image : NSManagedObject that has two properties: NSString* localPath and NSString* remoteUrl.
When I save the object by calling save:&error on the managed object context, I want it to download the file and when the download fails, I want the save operation to fail too.
Because I have a deeply nested DB structure with multiple references to my Image Entity it would be complicated to find all my images to trigger the download manually.
Is this possible, and if so, how can I cancel the save or delete operation so that it fails?
If it's bad practice to do this in the Model, where should I do this?
It's probably possible to do what you describe but it would be an incredibly bad idea. Downloading images can take a long time. Saving changes in Core Data can already take a while. Since saving will affect every instance that needs an image, you'd be taking a potentially long operation and turning it into a ridiculously, insanely, excessively long operation. Saving wouldn't complete until every image download had finished, and that's an extremely unreasonable dependency.
You'd be much, much, much better off having image downloading and saving changes completely decoupled from each other. Download images separately. If an object's image is unavailable, use a placeholder of some kind.
Instead of having save: start the download process, which by the way saves the entire managed object context not just a single object, I would start the download first. If the download succeeds, you can write the image to disk, update the localPath and save your changes, if it fails then you don't need to do a save at all.
I think that MVCS (Model View Controller Service / Model View Controller Store) might be of interest to you. You could move your logic to the Store layer. It would perform image download asynchronously and create NSManagedObject if download completed successfully.
You can find some information about it at: MVCS - Model View Controller Service and https://softwareengineering.stackexchange.com/questions/184396/mvcs-model-view-controller-store