Xcode / iOS: простой пример изменяемого C-массива как переменной экземпляра класса? - PullRequest
1 голос
/ 28 августа 2011

По какой-то причине я просто не могу разобраться с процессом создания переменной экземпляра C-Array для класса, в который можно динамически добавлять элементы во время выполнения.

Моя цель - создать класс с именем AEMesh. Все AEMesh объекты будут иметь c-массив, хранящий вершинные данные для этой конкретной 3D-модели AEMesh для использования с OpenGL ES (более конкретно, это функциональность для рисования модели путем передачи ей простого C-массива вершинных данных).

Изначально я использовал NSMutableArray, исходя из предположения, что я могу просто передать этот массив в OpenGL ES, однако это не так, поскольку для фреймворка требуется C-Array. Я обошёл эту проблему, по сути создав C-массив всех вершинных данных для текущего AEMesh, когда пришло время визуализировать эту конкретную сетку, и передав этот массив в OpenGL ES. Очевидно, что проблема здесь заключается в производительности, поскольку я постоянно выделяю и освобождаю достаточно памяти для хранения вершинных данных каждой 3D-модели в приложении около десятка раз в секунду.

Итак, я не тот, кому нужна ответная ложка, но если кто-то захочет объяснить мне стандартную идиому для предоставления классу изменяемого c-массива (некоторые статьи, которые я читал, упоминают с использованием malloc? ) Буду весьма признателен за это. Исходя из информации, которую я собрал, использование malloc может работать, но это не создает стандартный c-массив, который я могу передать OpenGL ES, а скорее его псевдо-c-массив, который работает как c-массив?

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

Спасибо, - Адам Эйсфельд

Ответы [ 3 ]

2 голосов
/ 28 августа 2011

Идея состоит в том, чтобы просто добавить указатель на массив структур AEMesh для вашего класса, а затем поддерживать массив по мере необходимости.Ниже приведен небольшой (непроверенный) код, который использует malloc () для создания такого массива и realloc () для его изменения.Я увеличиваю массив по 10 мешей за раз:

@interface MyClass : NSObject
{
    int meshCount;
    AEMesh *meshes;
}
@end

@implementation MyClass

-(id)init {
    if ((self = [super init])) {
        meshCount = 0;
        meshes = malloc(sizeof(AEMesh)*10);
    }
    return self;
}

-(void)addMesh:(AEMesh)mesh {
    if (meshCount % 10 = 0) {
        meshCount = realloc(sizeof(AEMesh) * (meshCount + 10));
    }
    if (meshCount != nil) {
        meshes[meshCount] = mesh;
        meshCount++;
    }
}
@end

Возможно, стоит включить управление массивом в свой собственный класс Objective-C, так как в ответе Брайана Колемана для управления используется std :: vectorсеткиТаким образом, вы можете использовать его для массивов C любого типа, а не только для AEMesh.

Из собранной мною информации использование malloc может работать, но это не создает стандартный c-массив Iможет передать в OpenGL ES вместо псевдо-c-массива, который работает как c-массив?

AC-массив - это не что иное, как серия объектов (здесь используются «объекты»)в смысле С смежной памяти, а не в смысле ОО) в памяти.Вы можете создать его, объявив его в стеке:

int foo[10];  // array of 10 ints

или динамически в куче:

int foo[] = malloc(sizeof(int)*10); // array of 10 ints, not on the stack
int *bar = malloc(sizeof(int)*10); // another way to write the same thing

Не забудьте использовать free () для освобождения любых блоков памятивы создали с помощью malloc (), realloc (), calloc () и т. д., когда закончили с ними.

1 голос
/ 28 августа 2011

Я знаю, что это не дает прямого ответа на ваш вопрос, но еще более простой подход - работать с переменной экземпляра NSMutableArray до тех пор, пока вам не понадобится передать ее в API, где вы будете использовать getObjects:range: для преобразовать его в C-Array. Таким образом, вам не придется иметь дело с «изменяемыми» C-массивами и избавите себя от проблем.

0 голосов
/ 28 августа 2011

Если вы хотите использовать ObjectiveC ++ и выходить за пределы C и ObjectiveC, то вы можете использовать std :: vector, чтобы амортизировать стоимость изменения размера массива данных вершин. Вот как бы это выглядело:

include <vector>
include <gl.h>

@interface MyClass {
    std::vector<GLfloat> vertexData;
}

-(void) createMyVertexData;

-(void) useMyVertexData;

@end

@implementation

-(void) createMyVertexData {
    // Erase all current data from vertexData
    vertexData.erase(vertexData.begin(), 
                     std::remove(vertexData.begin(), 
                                 vertexData.end());
    // The number of vertices in a triangle
    std::size_t nVertices = 3;
    // The number of coordinates required to specify a vertex (x, y, z)
    std::size_t nDimensions = 3;
    // Reserve sufficient capacity to store the vertex data  
    vertexData.reserve(nVertices * nDimensions);
    // Add the vertex data to the vector
    // First vertex
    vertexData.push_back(0);
    vertexData.push_back(0);
    vertexData.push_back(0);
    // And so on
}

-(void) useMyVertexData {
    // Get a pointer to the first element in the vertex data array
    GLfloat* rawVertexData = &vertexData[0];
    // Get the size of the vertex data
    std::size_t sizeVertexData = vertexData.size();
    // Use the vertex data
}

@end

Хороший момент заключается в том, что vertexData автоматически уничтожается вместе с экземпляром MyClass. Вам не нужно ничего добавлять к методу dealloc в MyClass. Не забудьте определить MyClass в файле .mm

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...