开发者

Serializing an array of "int"s in core data

开发者 https://www.devze.com 2023-03-14 04:44 出处:网络
I am trying to design my data-structures for a new App that I am working on, and I am using core data (for the first time).

I am trying to design my data-structures for a new App that I am working on, and I am using core data (for the first time).

I've been struggling a bit with working around the lack of arrays in core data, but I have mostly worked things out.

The one issue that I have left is that one of my object types has an array of "int"s. I may have LOTS of these ints, and so I want them to be space efficient. I also want to be able to access them quickly.

In my particular case, my array of ints will only have two operations performed on them. One is to iterate over them, and the second is to append new ints. The most common operation (and the one that I need to keep most efficient) is just being able to read all of the values in the array.

For storage, I figure that I need to use a "binary data" attribute on my object. Now I'm trying to figure out the best way to pack the "int"s into an array of bytes.

My app is going to create data that is only used on iOS devices for now, but may be used on other machines in the future, so I want to make sure that my solution is architecture independent, but at the same time fastest on iOS devices with slower processors and concern with battery life.

I'm currently thinking of designing my binary data so that the ints are stored in the "little endian" format. My object would be a sub-class of NSManagedObject, and it would hav开发者_开发问答e a side field (not part of the core data storage) which is an "int *" pointer which I would use to iterate over the values.

When my object is faulted into memory, I would initialize the c array. If the endianness is "little endian" (which I would determine using CFByteOrderGetCurrent()), then I can read the array of ints very efficiently with code like this:

@property (retain) NSData *data; // Core Data binary attribute
...
int *cArray = (int *) [self.data bytes];

If the endianness is not little-endian, I would need to allocate local storage, unpack the int values properly, and make keep both the binary attribute and the c-array up to date with changes.

I would add code to my sub-class to manage faults (i.e. nil-ing out the cArray when faulted out, and setting it properly when faulted back in).

So, I think I have a solution that should work for me, although I don't really like it.

If anyone can think of a better way to do what I am trying to do, I would really appreciate it.

Also, if anyone can think of reasons why interactions between the c-array and NSData or core data might cause me problems, I would really appreciate it.

Thanks, Ron


The typical method of performing this in CoreData would be to make a one-to-many relationship to an object of which only has a single field to hold your int value. Since you said you will have LOTS of these int values, this is more than likely not going to be a satisfactory solution.

You will also want to use caution with the binary type on your CoreData entities as this can often cause some undesirable issues related to performance while fetching if your binary data is big enough.

If neither of those options seem viable, you may want to consider dropping from CoreData down to a lower level storage mechanism which uses a more traditional database approach and would be able to efficiently perform all of your desired functions on your int values.


There are lots of fun things that the C standard allows:

  • Odd-sized bytes (9 is traditional)
  • Odd representations of signed numbers (e.g. sign-magnitude, ones complement)
  • Odd sizes of int (16 used to be common)
  • Unused bits in the memory representation

I'd personally use int32_t or (preferably) uint32_t and not worry about odd architectures. I also wouldn't bother with CFByteOrderGetCurrent(), since the byte order is known at compile time:

#include <TargetConditionals.h>

#if TARGET_RT_LITTLE_ENDIAN
  insert code here
#else
  #error "Big endian architectures not supported yet!"
#endif

I'd also use const int * (since NSData is not mutable).

There also might not be a guarantee that self.data will remain valid until the object turns into a fault — the general rule is "if you want an object to live, retain it". That said, Core Data probably holds on to the objects.

Finally, why do you need to store the int pointer in the object? I'd simply generate it on demand:

-(const int32_t*)intArray:(size_t*)count {
  NSData * d = [[self.data copy] autorelease];
  *count = [d length]/sizeof(int32_t);
  return (const int32_t*)[d bytes];
}

The copy/autorelease should be effectively free, but serves to ensure that the array you're iterating over doesn't change even if you set self.data during the iteration.

0

精彩评论

暂无评论...
验证码 换一张
取 消