Самый эффективный способ получить большой std :: vector в Swift? - PullRequest
0 голосов
/ 23 мая 2019

У меня есть класс Objective-C, который заполняет std:vector миллионами баллов.Структура вектора:

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

Итак, CGContour - это вектор CGPoints, а CGContours - это вектор CGContour.

Мне нужен доступэти данные в классе Swift как-то.Я не хочу использовать NSArray, потому что он имеет огромные накладные расходы по сравнению с использованием вектора (он как большой и медленный в 10 раз).

Какой самый эффективный способ получить миллионы CGPoints, доступных вСвифт из моего класса Objective-C?

Редактировать:

Я заполняю свой 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++;

}

1 Ответ

0 голосов
/ 23 мая 2019

Некоторые части недостаточно ясны, но я постараюсь показать вам пример.

Прежде всего, вам нужно подготовить класс, который может получить доступ к вашему contourVector. (Я не вижу, является ли это полем экземпляра или глобальной переменной, если это поле экземпляра, вы можете использовать существующий класс.)


Создайте заголовок для подготовленного класса, опять же, вы можете использовать существующий заголовок, но этот заголовок должен быть скомпилирован как в C-контексте, так и в C ++ контексте. Итак, если ваш существующий заголовок содержит какое-то объявление, которое не может быть скомпилировано в C-контексте, вам может понадобиться разделить два заголовка или несколько #if s.

#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, поскольку вы не можете создать UnsafeBufferPointer в Objective-C.

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!

Возможно, вам придется изменить некоторые части, чтобы они соответствовали вашему фактическому коду. Надеюсь, ты сможешь это сделать.

...