从 NSData 存储和恢复 std::vector

Storing and Restoring std::vector from NSData

我正在尝试将 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 缓冲区指针填充 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];
    }
}

像这样的东西应该可以解决问题。请注意我没有尝试编译这段代码,因为我在 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);
  }
}