如何使用CFData / NSData在CFIO中存储CFBitVector(或任何CFType)?

时间:2012-07-08 16:36:24

标签: ios core-data core-foundation cfdata cfbitvector

我在使用Core Foundation类型&收藏品,如果这很明显就道歉。

我正在使用CFBitVector类型来存储一些比特序列,我需要将其存储为二进制数据格式(以便可以将其添加到Core Data存储中)。最明智的做法似乎是将其存储在CFData类型中,可以使用NSData进行免费桥接并添加到商店,但我不确定如何执行此操作。< / p>

有人可以帮我解决一个在CF / NSData中存储CFType的简单例子吗?


修改

这甚至是正确的方法吗?我是否应该尝试将CFBitVector转换为一系列int,然后将其存储在数据模型中?或者也许是一个可转换的属性?

1 个答案:

答案 0 :(得分:3)

我最终这样做的方法是滚动我自己的属性转换器,以便将CFBitVectorRef转换为NSData实例。这样做的好处是我可以将位阵列紧紧地塞进一块二进制数据中,因为在我的情况下,我真的需要将存储大小保持在最低限度。

以下是我的CFBitVectorTransformer课程的实施情况。它基本上读取每个位并将它们打包到unsigned char s(下面的代码中的“段”),然后将它们附加到可变NSData缓冲区。代码适用于大于unsigned char s的类型,但是我希望最小的块可以实现最小化结果数据的大小。

#define kBitsPerByte    8


@implementation CFBitVectorTransformer


+ (Class)transformedValueClass
{
    return [NSData class];
}

+ (BOOL)allowsReverseTransformation
{
    return YES;
}

/* CFBitVectorRef -> NSData */
- (id)transformedValue:(id)value
{
    if (!value) return nil;
    if ([value isKindOfClass:[NSData class]]) return value;

    /* Prepare the bit vector. */
    CFBitVectorRef bitVector = (__bridge CFBitVectorRef)value;
    CFIndex bitVectorCount = CFBitVectorGetCount(bitVector);

    /* Prepare the data buffer. */
    NSMutableData *bitData = [NSMutableData data];
    unsigned char bitVectorSegment = 0;
    NSUInteger bytesPerSegment = sizeof(char);
    NSUInteger bitsPerSegment = bytesPerSegment * kBitsPerByte;

    for (CFIndex bitIndex = 0; bitIndex < bitVectorCount; bitIndex++) {
        /* Shift the bit into the segment the appropriate number of places. */
        CFBit bit = CFBitVectorGetBitAtIndex(bitVector, bitIndex);
        int segmentShift = bitIndex % bitsPerSegment;
        bitVectorSegment |= bit << segmentShift;

        /* If this is the last bit we can squeeze into the segment, or it's the final bit, append the segment to the data buffer. */
        if (segmentShift == bitsPerSegment - 1 || bitIndex == bitVectorCount - 1) {
            [bitData appendBytes:&bitVectorSegment length:bytesPerSegment];
            bitVectorSegment = 0;
        }
    }

    return [NSData dataWithData:bitData];
}

/* NSData -> CFBitVectorRef */
- (id)reverseTransformedValue:(id)value
{
    if (!value) return NULL;
    if (![value isKindOfClass:[NSData class]]) return NULL;

    /* Prepare the data buffer. */
    NSData *bitData = (NSData *)value;
    char *bitVectorSegments = (char *)[bitData bytes];
    NSUInteger bitDataLength = [bitData length];

    /* Prepare the bit vector. */
    CFIndex bitVectorCapacity = bitDataLength * kBitsPerByte;
    CFMutableBitVectorRef bitVector = CFBitVectorCreateMutable(kCFAllocatorDefault, bitVectorCapacity);
    CFBitVectorSetCount(bitVector, bitVectorCapacity);

    for (NSUInteger byteIndex = 0; byteIndex < bitDataLength; byteIndex++) {
        unsigned char bitVectorSegment = bitVectorSegments[byteIndex];

        /* Store each bit of this byte in the bit vector. */
        for (NSUInteger bitIndex = 0; bitIndex < kBitsPerByte; bitIndex++) {
            CFBit bit = bitVectorSegment & 1 << bitIndex;
            CFIndex bitVectorBitIndex = (byteIndex * kBitsPerByte) + bitIndex;
            CFBitVectorSetBitAtIndex(bitVector, bitVectorBitIndex, bit);
        }
    }

    return (__bridge_transfer id)bitVector;
}


@end

这很好地抽象了数据的转换,允许您在数据模型中将CFBitVectorRef设置为属性,并且应该足够快,以满足大多数用途。

我希望这可以帮助处于类似情况的其他人。