I'm building a messaging app, users of course can send text messages to each other, and now I want to add images sending support.
I have a NSManagedObject subclass ChatMessage to represent a chat message with properties like messageId, senderId, senderName, text, receiverId...
Now what is best practice to deal with the images?
I'm not talking about how to send and receive images, I'm talking about how to save them (when user get an image and when user upload and send an image)
Is it a good idea to add an image property to ChatMessage and save it with Core Data? or maybe save it to separate file? Do I need to resize them before saving? Should I expecte to have particular problems when I deal with images?
Eyal,
Core Data handles images well. In particular, in iOS v5 and Lion large BLOBs are stored outside of the persistent store. Small BLOBs are still stored in the DB. There are two caveats. First, in Core Data, it is very easy to create retain cycles, while this is never a good thing, a retain cycle involving large BLOBs will cause the OS to relatively quickly kill your process. As a result of this, the best practice is to create a leaf entity that just holds the BLOB and the inverse link. This makes it much less likely that you will create a retain cycle with the BLOB. I recommend that the relation to the BLOB be a to-one relationship. Second, large BLOBs cause memory warnings. Core Data does not appear to memory map these images into RAM. Hence, they cannot easily be automatically purged from your resident memory set. In my case, I have an app where I let CD handle the BLOBs. I also have an app where the BLOBs are quite large (12-24 MB). In the latter case, I handle the BLOB storage and memory mapping myself.
Whether you resize an image is really dependent upon your application and storage requirements/limitations. BLOB storage in CD doesn't affect this issue.
Andrew
Related
I am developing SpriteKit universal iOS application that will contain many spritekit images. I was wondering if there are better methods for working with large amount of data images in iOS apps from what's available as default from Apple (i.e. Core Data). Some resources point out that working with a database, like SQL, to save and load images data to/from a disk, improves the overall app performance in terms of memory resources.
What is the really best way to manage sprites content in the iOS application?
CoreData is an object graph management system first, and a front-end to a database second. Its intended use case it to manage models and their relationships to other models, much like tables in SQL. Therefore, it is not the correct solution for persisting binary data, such as an image. Flat file storage is definitely the better choice. Look into NSFileManager for writing files to disk.
If writing your own disk cache sounds like a daunting task, you should consider using a third-party framework. Nuke is a popular image cache written completely in Swift. It also handles fetching images over the Internet and provides extensions for integration with UIKit.
Alternatively, just search "image cache" on GitHub to see plenty of other options.
I have made couple of apps using coredata and I was storing images in sqlite, but somewhere i found that it is bad. I've searched the net but all I've found is this suggestion:
image size < 100kb store in the same table as the relevant data
image size < 1mb store in a separate table attached via a relationship
to avoid loading unnecessarily
image size > 1mb store on disk and reference it inside of Core Data
So my question is: what are pros and cons of saving an image in sqlite db as NSData, and storing just a reference to the image while image is saved in the file system?
Apple provide some guidance on this topic in their guide on Core Data Performance. In general, although SQLite scales pretty well and can handle databases that are many gigabytes in size with ease, large binary blobs are not queryable or indexable, and inflate the size of the database with little return.
If you're targeting iOS 4 and above, you can set the "Allows External Binary Data Storage" flag on your attributes that contain such data, and Core Data will automatically store them separately on the file system (if it deems appropriate), and automatically manage the link to that data in your data store.
Benefits: Not so sure, but I can think of couple of benefits of storing just links in the database.
The native code interaction with the file system would be faster than the SQLite image fetching. (overall faster performance)
Clean and scalable database -- (with size being the concern, migration would be easier)
You may want to check the answer I get for a similiar, if not the same, topic. Because as you I only found person giving advices, but no one really was providing benchmark and real technical answer.
Provide example for why it is not advisable to store images in CoreData?
Beside that, after my app have been realized with all images in db, and shipped to app store,
I can tell you that things are easier if you use iCloud. If you use small images in UITableView with thumbnail icons, you can completely avoid asynchronous image loading.
Only one advice, provide an entity for each images size, rather storing all in a set attached to main entity.
The only downside I found, with iCloud use, is the larger transaction log generated each time I change an image. But in my case image are small, and the needs of updating the images is rare. Also, iCloud+CoreData at the moment is quite buggy so I removed it before shipping, so at the moment it is really not a problem for me.
I have decided to give a try to saving images into CoreData as binary.
They are just small images from 2k to 90k maximum, and I can say I have trashed many lines of code, especially the ones dealing with iCloud issues.
Considering that CoreData is the only storage I put in iCloud using properties such as NSPersistentStoreUbiquitousContentNameKey, I have noticed that my sqlite file is actually about 1.6mb in size. While the total iCloud space occupied by the application itself, as seen in the iOS settings, is nearly 34mb, and I do not have any other documents around.
I already put the NSSQLiteManualVacuumOption as option, so I am wondering what is causing all this space to be taken. Probably the transaction log ?
You should be using External Data References.
With each change to the entity that stores your images you are writing out all of the image data. With external data references, the image data would be stored as a separate file, and can be deleted once it is no longer referenced.
I have an iOS 5.1 application that made use of CoreData in iCloud.
The user can take pictures and save it on iCloud too.
At the moment I am only saving an attribute picture YES or NO in an entity which should represent the event of taking picture, let say it's a kind of diary.
When YES I can calculate the path and retrieve the images. Actually there are three jpg images saved, a small to be used in UITableCell, a medium size for iPhone and a big size for iPad.
The maximum size can be at its maximum roughly 100kb.
Everything works fine, but I had to put some heavy logic into the app, for example to decide whether or not the images goes to iCloud, and in case of deletion if the images can be deleted too or moved locally.
In my development life I have never choosed to save images or binary in a DB, but this time I was thinking if the CoreData synchronization happening in the background could make my app more solid, and let me remove some lines of code. The idea is to add three attributes to the entity or probably for lazy issues, in another entity to be loaded as needed.
thanks
I would definately refrain from storing any image data in the database. I had an app that worked great where I stored thumbnails in the database. Once I attempted to move to iCloud I noticed a substantial increase in sync time due to the image data. I am talking several seconds to minutes if your database gets several entries. I am now storing everything in folders and testing diffrent ways to allow the user to decide which images they do or do not want saved in the cloud.
If your data entry will stay small I think it may stil be worth a shot, but develop know
I think it makes sense to store at least the small image in the DB. This should be very efficient, not be too network-intensive and - most importantly - would not make the iCloud store too big.
Apple is very adamant about "responsible" data storage in iCloud. See the section "Being a Responsible iCloud App" in the iOS Programming Guide. There it states
Apps that take advantage of iCloud storage features should act responsibly when storing data there. The space available in each user’s account is limited and is shared by all apps.
Thus, I would refrain from storing large images in your iCloud core data store.
I have a table of productList in which i have 4 column, now i have to store image for each row so i have two option for this..
Store image in data base.
Save images in a folder and store only path on table.
So my question is which one is better in this situation and why ?
Microsoft Research published quite an extensive paper on the subject, called To Blob Or Not To Blob.
Their synopsis is:
Application designers often face the question of whether to store large objects in a filesystem or in a database. Often this decision is made for application design simplicity. Sometimes, performance measurements are also used. This paper looks at the question of fragmentation – one of the operational issues that can affect the performance and/or manageability of the system as deployed long term. As expected from the common wisdom, objects smaller than 256K are best stored in a database while objects larger than 1M are best stored in the filesystem. Between 256K and 1M, the read:write ratio and rate of object overwrite or replacement are important factors. We used the notion of “storage age” or number of object overwrites as way of normalizing wall clock time. Storage age allows our results or similar such results to be applied across a number of read:write ratios and object replacement rates.
It depends -
You can store images in DB if you know that they wont increase in size very often. This has its advantage when you are deploying your systems or migrating to new servers. you dont have to worry about copying images seperately.
If the no. of rows increase very frequently on that system, and the images get bulkier, then its good to store on the file system and have a path stored in database for later retrieval. This also will keep you on toes when migrating your servers where you have to take care of copying the images from filepath seperately.