将大 std::vector 变成 Swift 的最有效方法?

Most efficient way of getting large std::vector into Swift?

我有一个 Objective-C class,其中包含数百万个点的 std:vector。向量的结构是:

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

所以 CGContour 是 CGPoints 的向量,CGContoursCGContour 向量的向量。

我需要以某种方式在 Swift class 中访问此数据。我不想使用 NSArray,因为与使用 vector 相比,它有巨大的开销(它大约是 10 倍大而且很慢)。

从我的 Objective-C class 获取 Swift 中的数百万 CGPoints 的最有效方法是什么?

编辑:

我正在像这样填充我的 CGContours 向量:

contourVector = CGContours(contours.size());
populatedContourNum = 0


//contours is OpenCV's contours
for( long c = 0; c < contours.size();  c++) {

    if (populatedContourNum >= contourVector.size()) {
        contourVector.resize(contourVector.size() + 1);
    }

    contourVector[populatedContourNum] = CGContour(contours[c].size());

    for( long pointNum = 0; pointNum < contours[c].size(); pointNum++ )
    {
        contourVector[populatedContourNum][pointNum] = CGPointMake(contours[c][pointNum].x * scale,
                                                                         contours[c][pointNum].y * scale);
    }

    populatedContourNum++;

}

有些部分不够清楚,但我会尝试向您展示一些示例。

首先你需要准备一个class可以访问你的contourVector。 (看不出是实例字段还是全局变量,如果是实例字段,可以用已有的class。)


为准备好的class创建一个header,同样你可以利用现有的header,但是这个header需要在[=46=中编译] 和 C++ 上下文中。因此,如果您现有的 header 包含一些无法在 C-context 中编译的声明,您可能需要分隔两个 header 或一些 #if

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface YourClass : NSObject

- (NSInteger)contoursSize;
- (NSInteger)contourSizeAtIndex:(NSInteger)index;
- (CGPoint *)contourAtIndex:(NSInteger)index;

//...

@end

NS_ASSUME_NONNULL_END

然后在header指定的class中添加3个方法:

#import "YourClass.h"
#import <vector>

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

static CGContours contourVector;

@implementation YourClass

- (NSInteger)contoursSize {
    return contourVector.size();
}
- (NSInteger)contourSizeAtIndex:(NSInteger)index {
    return contourVector[index].size();
}
- (CGPoint *)contourAtIndex:(NSInteger)index {
    return contourVector[index].data();
}

@end

请不要忘记在 Project-Bridging-Header.h:

中包含 header
//
//  Use this file to import your target's public headers that you would like to expose to Swift.
//

#import "YourClass.h"

您需要创建一个 Swift 侧包装器 class,因为您无法在 Objective-C.

中创建 UnsafeBufferPointer
class YourClassWrapper {
    let yourInstance = YourClass()

    var count: Int {
        return yourInstance.contoursSize()
    }

    subscript(index: Int) -> UnsafeBufferPointer<CGPoint> {
        guard 0..<count ~= index else {fatalError("Index \(index) out of bounds \(0..<count)")}
        let start = yourInstance.contour(at: index)
        let count = yourInstance.contourSize(at: index)
        return UnsafeBufferPointer(start: start, count: count)
    }
}

通过以上这些准备,您可以访问每个 CGPoint 作为:

let wrapper = YourClassWrapper()
let point = wrapper[0][1]

或者您可以获得指向 CGContour 中第一个元素的指针:

let ptr = wrapper[0].baseAddress!

您可能需要修改某些部分以使其适合您的实际代码。希望你能成功。