내가이 일을 끝낸 방식은 CFBitVectorRef
을 NSData
인스턴스로 변환하기 위해 자체 특성 변환기를 롤업하는 것이 었습니다. 이것의 이점은 비트 배열을 바이너리 데이터의 블록에 단단히 밀어 넣을 수 있다는 것입니다. 필자의 경우에는 스토리지 크기를 최소한으로 유지해야합니다.
다음은 내 CFBitVectorTransformer
클래스의 구현입니다. 기본적으로 각 비트를 읽고이를 unsigned char
(아래 코드의 "세그먼트")에 압축 한 다음 가변적 인 NSData
버퍼에 추가합니다. 이 코드는 unsigned char
보다 큰 유형에서도 작동하지만 결과 데이터의 크기를 최소화하려면 가능한 한 가장 작은 청크가 필요했습니다.
#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
을 설정하고, 충분히 충분히 빨리 대부분의 목적을 위해해야하므로 데이터의 변환을 추상화합니다.
나는이 상황이 다른 누군가에게 도움이되기를 바랍니다.
문제가 생겼습니다. 즉, - (id) reverseTransformedValue : (id) value', * bit *가 1 일 때, 2,4,64,128 등의 값을 얻었습니다. 'CFBitVectorSetBitAtIndex (bitVector, bitVectorBitIndex, bit! = 0)'을 수동으로 할 필요가있다. 버그인지 또는 코드를 올바르게 사용하지 않았는지 확실하지 않습니다. – BabyPanda