从NSData存储和恢复std :: vector

时间:2016-05-01 20:11:46

标签: c++ objective-c nsdata stdvector

我试图将std :: vector存储到NSData并直接返回。我的第一次尝试是将每个点转换为NSValue并使用NSKeyedUnarchiver存储它们,这看起来非常低效。我的测试数据集需要64MB的人类可读文本(使用NSKeyedUnarchiver),而不是将每个std:vector转换为NSData,生成的存储文件更加合理896kb。我按照以下方式存储数据:

    typedef std::vector<CGPoint> CGContour;
    typedef std::vector<std::vector<CGPoint>> CGContours;
    static CGContours contoursVector;

    contoursVector = CGContours(1024); //Populated with CGContours that are populated with CGPoints datatypes above

    //doing the following in a for loop, just showing record 0 for brevity
    NSData *contourData([[NSData alloc]
                       initWithBytesNoCopy: contoursVector[0].data()
                       length: contoursVector[0].size()
                       freeWhenDone:false]);

我能够检索缓冲区:

    const void *buffer = [contourData bytes];
    size_t len = [contourData length];

但是,我无法弄清楚如何使用const void buffer指针填充std :: vector。我已经尝试过使用我能想到的每个可能的指针和解除引用组合 - 我可以编译的唯一一件事是:

   contoursVector[0] = *(CGContour *)[contourData bytes];

如果我检查CGPoints的向量,它们是0,0,那么显然有些不对。

编辑:在实施建议的答案后,有时它会起作用,有时我会得到EXC_BAD_ACCESS。以下是相关的回溯:

* thread #17: tid = 0x11bf7d4, 0x0000000111607551 libsystem_platform.dylib`_platform_memmove$VARIANT$Ivybridge + 49, queue = 'NSOperationQueue 0x7fa298f51000 :: NSOperation 0x7fa29f3251f0 (QOS: UTILITY)', stop reason = EXC_BAD_ACCESS (code=1, address=0x126e27000)
frame #0: 0x0000000111607551 libsystem_platform.dylib`_platform_memmove$VARIANT$Ivybridge + 49
frame #1: 0x000000010d01890f Foundation`NSCopyMemoryPages + 57
frame #2: 0x000000010cf9b737 Foundation`_NSDataCreateVMDispatchData + 103
frame #3: 0x000000010cf99cf2 Foundation`-[_NSPlaceholderData initWithBytes:length:copy:deallocator:] + 230
frame #4: 0x000000010cfa5902 Foundation`-[NSData(NSData) initWithBytes:length:] + 37
* frame #5: 0x000000010cfeabfb Foundation`+[NSData(NSData) dataWithBytes:length:] + 54
frame #6: 0x000000010c5c998a TDTPhotoLib`storePointData() + 682 at TDTContourImage.mm:562

奇怪的是,轮廓和转换为数据的轮廓在调试器中看起来都是有效的并且问题似乎是间歇性的(有时它会起作用,但它无法解释如果任何事情可能都不同)

编辑2:

我可以遍历每个点,但它在NSData线上崩溃。

NSMutableArray<NSData *> *groupedPointsArrayMain = [NSMutableArray new];

for(const CGContour &contour : contoursVector)
{
    if (contour.size() > 0) {

        // I am able to iterate over every point and store them this way
        NSMutableArray *contourPoints = [NSMutableArray arrayWithCapacity:contour.size()];

        for(const CGPoint &point : contour)
        {
            [contourPoints addObject:[NSValue valueWithCGPoint:point]];
        }

        //When it crashes, it will crash on this line
        //despite it successfully walking over each point
        //in the code directly above
        NSData *data = [NSData dataWithBytes: contour.data()
                                      length: (contour.size() * cgContourSize)];

        [groupedPointsArrayMain addObject:data];
    }
}

1 个答案:

答案 0 :(得分:1)

这样的事情应该可以解决问题。请注意,因为我在Linux atm上,所以我没有尝试编译此代码。

typedef std::vector<CGPoint> CGContour;
typedef std::vector<CGContour> CGContours;

const size_t contourSize = sizeof(CGContour);

NSMutableArray<NSData *> *datas = [NSMutableArray new];

{ // store
  CGContours contours(1024);

  for(const CGContour &contour : contours)
  {
    NSData *data = [NSData dataWithBytes: contour.data()
                                  length: contour.size() * contourSize];
    [datas addObject:data]
  }
}

{ // restore
  CGContours contours;

  for(NSData *data in datas)
  {
    const size_t count = [data length] / contourSize;
    CGPoint *first = (CGPoint *)[data bytes];
    CGPoint *last = first + count;

    contours.emplace_back(first, last);
  }
}