I would like to store a ABRecordRef in a 'Client' entity in core data.
I have read in apples documentation that ABRecordRef is a primitive C data type. As far as I am aware, you can only insert objects in core data. With this in mind, what is the best way to store it in core data?
I thought about converting it into a NSNumber for storage, but dont know how to convert it back to ABRecordRef for use.
I also thought I could just put it in a NSArray/NSSet/NSDictionary on its own just acting as a wrapper but didnt know if this was silly/inefficient/would even work.
Thoughts appreciated.
Many thanks
In one of my apps I just stored the ABRecordGetRecordID() as a INT32 in the CoreData store (since an ABRecordID is a int32_t) and also stored the contact name in the CoreData store for quick display purposes. That way the Record information is stored in the AddressBook where it belongs and you have just stored a "pointer" to the record in your CoreData store.
You could then create handy wrapper accessors in your custom Client NSManagedObject that would wrap the C calls to the AB framework to suit your needs.
Related
I use Cocoa's Core Data framework which has the possibility of writing the data to XML via NSXMLStoreType.
For Copy & Paste in my app would I now like to write some core data objects to NSPasteboard and read it from there again. I thought that it should be able to read and write the in-build XML representation. Of course could I create a Codable interface for my core data classes, but I rather reuse the core data implementation.
How can I do this best?
Many thanks in advance!
The problem with this strategy is that the details of the XML store's schema implementation is internal to Apple. If you're going to use the results with another XML store, you should be ok. But I wouldn't expect the XML schema Apple uses to lend itself to being useful outside of that context, as it is written to disk, or depend on it not to change.
You can specify the store type when configuring an instance of NSPersistantContainer by setting its persistentStoreDescriptions property. NSPersistentStoreDescription has a type property, which can be set to NSXMLStoreType.
I am new with Core Data and wanted to know if I should use it or not. I want an entity to only have one record which has a bunch of attributes. Should I be using something else or is Core Data fine for this?
For example: I have a user's home entity and it has a bunch of attributes about the house, but I expect the user to have only one home.
You should make your model class to be NSCoding compliant and store it on NSUserDefaults. Using core data to store only one record brings the overhead of the core data stack, and it's a hefty price for only 1 record.
I've been trying to build a simple load/save system for a game using Core Data.
Saving, loading and creating my UIManagedDocument works fine. Setting and loading values for attributes in my savegame entity works fine as well.
The problem is that these values are lost when my app quits, because I don't know how to access them.
I have about 200 attributes inside my savegame entity, such as (NSNumber *)currentIncome, NSNumber *currentMoney, NSNumber *currentMonth etc. Seems simple, right? If I were to group these into attributes with relationships, I'd probably end up with about 20 attributes. From what I gathered from the Core Data Programming Guide, in order to fill the entity with the values from my saved UIManagedDocument, I need to perform a fetchrequest with a predicate which fills an array of results.
This is where my first question arises: Would I need to perform a fetchrequest for every single attribute? This seems useful if you only have a few attributes or if you have 'to many' relationships. In my case, this would seem incredibly tedious though.
I might be missing something very essential here, but I would need something like load my UIManagedDocument and automatically fill my NSManagedModel with the one that was saved in the document's context and I cannot find it.
That is where my second question comes in: Is CoreData and UIManagedDocument even the right approach for this? 200 variables is too much for NSUserDefaults - I could imagine using NSCoding though. I definately want to incorporate iCloud savegame sharing at a later point, and UIManagedDocument and CoreData just seemed perfect for this.
Solved:
I just rewrote the entire Core Data fetching code (20 lines down to 10 or so).
Performing a fetchrequest for an entity without a predicate apparently returns the entire entity.
If my (NSArray *)fetchedResults turns up nil (database is empty), I insert a new instance of my savegame entity in my managedobjectcontext.
If it turns up non-nil, I just do a (NSManagedObject *)saveGame = [fetchedResults lastObject] and every value gets loaded fine.
From a database perspective it sounds like what you have here is a database with a single table saveGame with 200 columns currentMoney, currentMonth, etc. You then have a single row in your database representing the current game state.
The NSFetchRequest is the equivalent of the database SELECT statement, and as you only have one row you don't really need any predicates WHERE clauses etc, just get everything from this table, which is what your fetch request that only specifies the entity is doing SELECT * FROM saveGame.
So all in all it doesn't sound like you're getting much value out of the core-data framework here. Another alternative might be to look into the iCloud Key-Value storage API, which sounds closer to what you are currently getting from core-data.
I have been searching for some sample code on how to store an NSArray in Core Data for awhile now, but haven't had any luck. Would anyone mind pointing me to some tutorial or example, or better yet write a simple sample as an answer to this question? I have read this but it doesn't show an example of how to go about implementing a transformable attribute that is an NSArray. Thanks in advance!
If you really need to do it, then encode as data. I simply created a new filed called receive as NSData (Binary data).
Then in the NSManagedObject implementation:
-(void)setReceiveList:(NSArray*)list{
self.receive = [NSKeyedArchiver archivedDataWithRootObject:list];
}
-(NSArray*)getReceiveList{
return [NSKeyedUnarchiver unarchiveObjectWithData:self.receive];
}
Transformable attributes are the correct way to persist otherwise unsupported object values in Core Data (such as NSArray). From Core Data Programming Guide: Non-Standard Persistent Attributes:
The idea behind transformable attributes is that you access an attribute as a non-standard type, but behind the scenes Core Data uses an instance of NSValueTransformer to convert the attribute to and from an instance of NSData. Core Data then stores the data instance to the persistent store.
A transformable attribute uses an NSValueTransformer to store an otherwise unsupported object in the persistent store. This allows Core Data to store just about anything that can be represented as NSData - which can be very useful. Unfortunately, transformable attributes cannot be matched in a predicate or used in sorting results with the NSSQLiteStoreType. This means that transformable attributes are useful only for storage, not discovery of objects.
The default transformer allows any object that supports NSCoding (or NSSecureCoding) to be stored as a transformable attribute. This includes NSArray, UIColor, UIImage, NSURL, CLLocation, and many others. It's not recommended to use this for data that can be arbitrarily large, as that can have a significant performance impact when querying the store. Images, for example, are a poor fit for transformable attributes - they are large bags of bytes that fragment the store. In that case, it's better to use the external records storage capabilities of Core Data, or to store the data separately as a file, and store the URL to the file in Core Data. If you must store a UIImage in Core Data, be sure you know the trade offs involved.
Creating a transformable attribute is easy:
• In the Xcode Core Data Model Editor, select the model attribute you want to modify. In the right side inspector, set the attribute type as "Transformable". You can leave the "Name" field blank to use the default transformer. If you were using a custom transformer, you would enter the class name here and register the class using +[NSValueTransformer setValueTransformer:forName:] somewhere in your code.
• In your NSManagedObject subclass header declare the property that describes the transformable attribute with the correct type. In this case, we're using NSArray:
#property (nonatomic, retain) NSArray *transformedArray;
• In the NSManagedObject subclass implementation file the property should be dynamic:
#dynamic transformedArray;
And you are done. When an NSArray value object is passed to setTransformedArray: that array is retained by the object. When the context is saved Core Data will transform the NSArray into NSData using the NSValueTransformer described in the model. The NSData bytes will be saved in the persistent store.
You don't store an NSArray natively in Core Data. You need to transform the values stored within the array into something Core Data can use, and then save the data in the store so that you can push and pull it to your NSArray as needed.
Philip's answer is right. You don't store arrays in Core Data. It is totally against what Core Data is made for. Most of the time you don't need the information of the array but one and that one can get dynamically loaded by Core Data. In the case of collections, it makes no difference if you iterate through an array of your whatever properties or of an array of fetched results on an NSSet (which is basically just an array too).
Here is the explanation what Philip said. You can't store an array directly, but you can create a property list from it. There is a method in all NS Arraytypes that gives you a nice and clean string and core data love strings. The cool thing about property lists stored as strings is, they can become what they were. There is a method for that in NSString. Tataaa...
There is a price of course.
Arrays as property lists can get gigantic and that doesn't go well with iOS devices where RAM is limited. Trying to save an array to core data indicates a poor entity design especially for large data. A small array is OK for speed reasons.
Another, less space consuming way, is to use binary property lists. Those come close to zip sizes when stored in Core Data or directly in the filesystem. Downside is, you can't simply open and read them like an XML or JSON file. For development I prefer something human readable and for release the binary version. A constant tied to the DEBUG value in the preprocessor takes care of that, so I don't have to change my code.
Core Data stores instances of NSManagedObject or subclasses of same. NSManagedObject itself is very much like a dictionary. To-many relationships between objects are represented as sets. Core Data has no ordered list that would correspond to an array. Instead, when you retrieve objects from a Core Data store, you use a fetch request. That fetch request can specify one or more sort descriptors that are used to sort the objects, and the objects returned by a fetch request are stored in an array.
If preserving the order of objects is important, you'll need to include an attribute in your entity that can be used to sort the objects when you fetch them.
I need to store large amount of data using RMS API through J2ME.
How can I store that multiple-column data, given they must be hardcoded so I need to store those multiple columns and rows data.
How can I do this in this, should I use structs?
Well, RMS only allows you to store records that are arrays of bytes. You will have to decide for yourself how a record is stored, and if you want to store your data in a single or in multiple records. If you use the DataInputStream and DataOutputStream classes, you'll be able to read/write Strings, booleans, integers, etc. The API documentation includes a decent example of how you can do this.
If you have complex data to store, or a lot of different objects, you may want to create a simple library for RMS I/O, that allows you to pass objects implementing e.g. "Storable" to a library class that writes away your object into RMS.
See my question on exacty the same topic. In the end we bought a commercial BTree imeplementation and extended it to work across multiple record stores.
Has Jeroen said RMS is quite basic. You can only store arrays of bytes. But, though it's basic, it's quite easy implement a more complex memory structure with an index stored in a record store and addressing other record stores containing data.
Have a look to this page : Understanding the Record Management System