Transformable images stored in CoreData - will it work with pre-seeded database? - ios

If I use the "Transformable" attribute in Core Data to store images, it is my understanding that Core Data may or may not store it in the persistent store based on file size. Normally I wouldn't care where it stored the image, but for this app I need to ship it with a pre-seeded database in case an internet connection is not found when the app is first launched. So I basically want to take a snapshot (including images) of the database and have it load the first time the app is launched.
My question is, if Core Data decides for whatever reason to not use the persistent store, will the images still get loaded when I load the pre-seeded database? Or will it be broken because the image(s) were stored in some magic area that no longer exists when the user installs on their own device?

Making an attribute transformable has nothing to do with using external storage. The Store in External Record File option is available for both binary attributes and transformables, but is not required for either.
If you have an attribute that is transformable and uses external record files, you're correct that Core Data decides whether to actually use an external file based on its own undocumented logic (but probably by checking the size). Those external files get saved in a subdirectory of the one where the data store is located. If your data store is named Foo.sqlite, then in the same directory where that file is found is a directory named .Foo_SUPPORT/_EXTERNAL_DATA/. You can deal with this in a couple of ways:
Copy the entire directory where Foo.sqlite lives, including dot files. This is preferred, because the path to the external references directory is undocumented and (in theory) could change. You'll get the external references but you don't need to hard-code the directory name.
Copy the directory directly, since you know where it is. Probably a less good idea, for reasons described above.
Or if you prefer, just don't use external references. They're not required for any attribute, and if you like you can just have all of your data in a monolithic SQLite file.

You can just tell core data to use external storage for your images, and make it not having to figure it out when to use it and use it all the time. You can find the option to assign a property to use external storage on the core data inspector of your property.

Related

Storing CoreData to RackSpace

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.

iOS app: Pre-populated large database not allowed - alternatives?

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.

Solution For Monitoring and Maintaining App's Size on Disc

I'm building an app that makes extensive use of CoreData and a lot of my models have UIImage and NSData properties (for images and videos). Since it's not a great idea to store that data directly into CoreData, I built a file manager class that writes the files into different buckets in the documents directory depends on the context in which was created and media type.
My question now is how do I manage the documents directory? Is there a way to detect how much space the app has used up out of its total allocated space? Additionally, what is the best way to go about cleaning those directories; do I check every time a file is written or only on app launch, ect ect.
Is there a way to detect how much space the app has used up out of its total allocated space?
Apps don't have a limit on total allocated space, they're limited by the amount of space on the device. You can find out how much space you're using for these files by using NSFileManager to scan the directories. There are several methods that do this in different ways-- check out enumeratorAtPath:, for example. For each file, use a method like attributesOfItemAtPath:error: to get the file size.
Better would be to track the file sizes as you create and delete files. Keep a running total, stored in user defaults. When you create a new file, increase it by the amount of new data. When you remove a file, decrease the running total.
Additionally, what is the best way to go about cleaning those directories; do I check every time a file is written or only on app launch, ect ect.
If these files are local data that's inherently part of the associated Core Data object, the sensible approach is to delete a file when its Core Data object is deleted. The managed object needs the data file, so don't delete the file if you still use the object. That means there must be some way to link the two, but I'm assuming that's already true since you say that these files are used by managed objects somehow.
If the files are something like cached data that's easily re-created or re-downloaded, you should put them in the location returned by NSTemporaryDirectory(). Then iOS can delete them when it thinks the space is needed. You can also clear out old files whenever it seems appropriate, by scanning for older files or ones that haven't been used in a while (the details depend on exactly how you use the files).

Storing blobs in external location using built-in CoreData option

I have managed objects that have image properties. Since storing large blobs in CoreData is a bad idea, I'm trying to use the built-in CoreData option "Store in External Record File" which you can see in the Data Model Inspector.
Despite enabling this option, I do not see any image data being stored externally. Judging by the size, it seems like they are still being saved in the sqlite file. What is the issue?
If your store type is NSSQLiteStoreType, your attribute is NSBinaryDataAttributeType. You have enabled setAllowsExternalBinaryDataStorage and your object data size is larger then approximately 1MB.
Objects that are smaller than 1MB are stored in the sqlite database.
Objects that are larger are just a reference to a external file.
You'll find the (external) files in a hidden sub-directory at the same location as the persistent store.
<path>/<database>.sqlite
<path>/<your_database>_SUPPORT/_EXTERNAL_DATA/
sqlite2 does not allow size of BLOB data to be more than 1MB,However sqlite 3 allows larger BLOB.First check out which version of sqlite u r using.
And if ur file is in MB's i would rather prefer them storing in local database instead.

Core data keep creating A Document Being Saved... folders

I am using Core Data with a prepopulated Store with an entity that has Binary Data with External Storage checkbox enabled to save some large images externally, and every time I run the app in the simulator and executing a fetch request, a new folder called "A Document Being Saved by AppName" inside Documents is created.
The folder contains some of the images I fetched when running the app.
The problem is this folder doesn't delete on application termination, and the app keeps increasing in size currently weighting several GB!
I have started this project using the default Xcode template with Core Data enabled.
Did I Miss something ?
Bill,
That folder is a temporary store for the externally saved BLOBs. The folder is normally emptied when the save is finished. If you crash though during the save, then the data is left behind for you to handle. I normally delete the directories on startup. Basically, if the BLOB isn't moved into the CD hidden BLOB directory, then it isn't in the DB. In my application, I've had no problem. Your mileage may vary.
Andrew
Since you're using Core Data it seems likely that you want the data that your app generates to persist, right? If so, then deleting its data store when the app terminates doesn't seem very helpful. (Also, the user really shouldn't care whether the app has actually terminated or not.) Perhaps your app should instead monitor the number of images it has stored and delete the old ones as it goes along?

Resources