将大 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 的向量,CGContours
是 CGContour
向量的向量。
我需要以某种方式在 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!
您可能需要修改某些部分以使其适合您的实际代码。希望你能成功。
我有一个 Objective-C class,其中包含数百万个点的 std:vector
。向量的结构是:
typedef std::vector<CGPoint> CGContour;
typedef std::vector<CGContour> CGContours;
所以 CGContour
是 CGPoints 的向量,CGContours
是 CGContour
向量的向量。
我需要以某种方式在 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
:
//
// 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!
您可能需要修改某些部分以使其适合您的实际代码。希望你能成功。