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!
-
Please refer http://stackoverflow.com/questions/29825604/how-to-save-array-to-coredata/40101654#40101654 – Vinoth Anandan Oct 18 '16 at 07:17
5 Answers
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];
}

- 8,508
- 6
- 35
- 57

- 6,500
- 3
- 32
- 40
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.

- 21,123
- 4
- 76
- 83
-
-
Quellish - great answer but may I trouble you to extend your answer to cover code blocks as transformable objects as well without editing the auto-generated category definitions that XCode provides from the model? There is virtually no data on this anywhere and, like the questioner, I'm at a complete loss as to how to achieve this. Thanks in advance if you don't mind. – VectorVictor Sep 18 '17 at 08:10
-
@VectorVictor I am not sure what you mean by code blocks as transformable objects – quellish Sep 18 '17 at 08:12
-
Thanks for your prompt reply, Quellish. In a nutshell, one of my attributes in my model is a code block [void (^myType)(CGRect rect1, CGRect rect2)] which holds a 'user-selectable' function to use in the app. There will, potentially, be hundreds of these things but I don't want them all available in the app simultaneously 1) to reduce footprint and 2) the database of these things will be shipped as a readonly library. How can I store my blocks in Core Data? (I've had no problem testing them in NSDictionary - so it must be feasible.) Thanks again! – VectorVictor Sep 18 '17 at 08:47
-
Quick update, Quellish. The principle problem I hit is an unrecoginised selector error when Core Data comes to write the NSManagedObjectContext out to disc. After a painful period of investigation I've tracked this down to an encoding problem. Basically, the blocks need to be stored as NSData but one can't invoke
for obvious reasons. It needs a subclass of NSValueTransformer applied to the code blocks - but that's where the Internet and Apple dry up! – VectorVictor Sep 18 '17 at 08:55 -
@VectorVictor wait, you're trying to archive a *block*? That would not work nor would it make sense. A block is a segment of code and captures enclosing scope. It would make little sense to archive it at all, much less with core data. – quellish Sep 18 '17 at 09:08
-
Thanks for this, Quellish. I now understand how blocks are stored internally. Their ability to exist as 'id's led me to think that they were capable of more than I realised. Their *entry addresses* are the 'id's! It looks as if my app is going to be a lot bigger than I had hoped. Many, many thanks for your help. It's all clear now. – VectorVictor Sep 18 '17 at 09:20
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.

- 5,005
- 2
- 25
- 39
-
11Voted down with no comment? Not terribly helpful especially since the answer isn't actually wrong. – Philip Regan Mar 09 '11 at 12:13
-
that something that core data can use would be another `entity` in your core data model that's connected to your original `entity` via a to-many relationship (assuming all your NSArray objects are of the same class). – ryantuck Jun 28 '14 at 16:16
-
6The question is about *transformable attributes*, which are an entirely appropriate way to store an NSArray or other complex object in Core Data. – quellish Aug 26 '14 at 19:38
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.

- 19,551
- 4
- 71
- 68

- 3,219
- 1
- 20
- 33
-
1Please don't assume that the original poster voted answers down, gives tart taste to an already sour post. Thanks for the nice explanation though. – Stunner Nov 13 '12 at 11:52
-
3Ouch. Yes I did mistranslate this and responded more emotionally. I am real sorry for that. – Helge Becker Apr 05 '13 at 10:30
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.

- 124,013
- 19
- 183
- 272