【问题标题】:Most efficient way of getting large std::vector into Swift?将大型 std::vector 放入 Swift 的最有效方法?
【发布时间】:2019-05-22 23:08:14
【问题描述】:

我有一个 Objective-C 类,它用数百万个点填充 std:vector。向量的结构是:

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

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

我需要以某种方式在 Swift 类中访问这些数据。我不想使用 NSArray,因为与使用矢量相比,它有巨大的开销(它的大小和速度差不多是 10 倍)。

从我的 Objective-C 类中获取 Swift 中可访问数百万个 CGPoint 的最有效方法是什么?

编辑:

我正在像这样填充我的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++;

}

【问题讨论】:

  • 你可以使用Objective-C++创建一个包装std::vector的ObjC类,并暴露它的指针,这样它就可以在Swift中变成Unsafe(Mutable)BufferPointer&lt;CGPoint&gt;。它会工作,但它需要一些内存管理,如果向量的缓冲区无效,它将失败
  • 谢谢!你能在答案中举一个例子吗?
  • 不,我从未尝试过。我只是给你一个大致的调查方向
  • 如果你想要一个具体的例子,请使用这些类型展示你的 Objective-C++ 代码。
  • 谢谢!我添加了填充向量的方式。

标签: arrays objective-c swift nsarray stdvector


【解决方案1】:

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

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


为准备好的类创建一个头文件,你可以再次使用现有的头文件,但是这个头文件需要在 C 上下文和 C++ 上下文中编译。因此,如果您现有的标头包含一些无法在 C 上下文中编译的声明,您可能需要分隔两个标头或一些 #ifs。

#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

然后在头部指定的类中添加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 侧包装类,因为您无法在 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!

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

【讨论】:

  • 太棒了,谢谢!我会尽快试一试并报告。再次感谢!
  • @OOPer 您如何看待将此数据公开为UnsafeBufferPointer&lt;CGPoint&gt;?您可以获得符合 Collection 的所有便利,但我自己没有尝试过,所以 IDK 可能有什么缺点
  • @Alexander,OP 的contourVector 是向量的向量,内部向量是std::vector&lt;CGPoint&gt;,所以UnsafeBufferPointer&lt;CGPoint&gt; 适合内部向量(如我的回答)。但是你想怎么管理外向量呢?
  • @OOPer 啊,我错过了那个细节。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-25
  • 2021-05-29
  • 2017-08-22
  • 2021-07-27
  • 2011-12-15
  • 2013-04-19
相关资源
最近更新 更多