2010-01-03 10 views
5

Para optimizar un cuello de botella, convertí la creación de un NSArray grande en una matriz de estilo c. (La creación resultante fue 1/8 del tiempo de la versión original de NSArray. ¡Sí!) Pero una vez que se ha creado, la velocidad ya no es un problema, así que prefiero beneficiarme de que vuelva a ser un NSArray.¡Tiene que haber una manera más fácil de manejar matrices!

Sin embargo, parece ridículamente trata de convertir una matriz C de estilo a un NSArray (a menos que me falta algún método initWithArrayWrapElementsInObjects magia.)

Según entiendo el proceso ahora, primero tengo que crear una NSMutableArray , itere a través de la matriz c-style convirtiendo cada elemento (floats en mi caso) en objetos, agregando cada objeto al NSMutableArray, luego creando el NSArray con NSMutableArray.

¿Es correcto? Tiene que haber una mejor manera.

Y la ayuda sería apreciada.

Gracias!

Respuesta

7

No hay una forma directa de tomar una burbuja de memoria que usted posee y "convertirla" a bajo precio en una NSArray-- después de todo, la estructura necesitaría entonces poseer esa memoria, y no sabe dónde se metió de (malloc, pila, etc.). Si hubiera un método de conveniencia para initWithArrayWrapElementsInObjects, tendría que hacer internamente lo que supones: iterar sobre la memoria proporcionada y agregar elementos a sí mismo (es posible que el framework pueda hacer esto tan rápido como memcpy, pero quién sabe).

Una forma de abordar esto (y probablemente un divertido ejercicio de aprendizaje) consiste en crear su propia subclase de NSArray que administre la memoria exactamente como desee (es decir, le permite crear e iniciar con la semántica que desee), pero que se comporta con el mundo exterior como lo haría un NSArray. Puede hacerlo heredando de NSArray e implementando los métodos count: y objectAtIndex: para operar en cualquier memoria que tenga. Obviamente, necesitaría implementar la administración de su propia memoria en los métodos init/dealloc, etc. Consulte esta página http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray.html en "Subclassing Notes".

La discusión de diseño aquí depende de cómo se vean sus datos. NSArray, por supuesto, espera que sus artículos sean referencias Obj-C (del tipo id), y no solo fragmentos arbitrarios de datos. Si su matriz estilo C retiene estructuras u otros valores primitivos que no son referencias a objetos, entonces esta técnica no funcionará para usted: la interfaz de NSArray nunca estará contenta con elementos que no sean de referencia.

Una nota final: mencionas tomar un NSMutableArray y "crear" un NSArray con él. Debe tener en cuenta que un NSMutableArray ya es un NSArray, ya que es una subclase. Puede usar una instancia de NSMutableArray en cualquier lugar en el que desee un NSArray, sin crear una copia nueva de este.

ACTUALIZACIÓN: Faltó la nota sobre su matriz que contiene flotadores. Sí, estás un poco jodido aquí. NSArrays quiere objetos. Si la duplicación de la capacidad era la parte más costosa (como señala otro afiche), intente con initWithCapacity :. Si es el boxeo/unboxing de los flotadores en tipos de objetos, no hay nada que puedas hacer.

He creado (pero no tengo a mano) un par de clases muy simples (llamadas como MYArray y MYMutableArray) que están destinadas a envolver solo este tipo de datos con métodos similares a NSArray. Pero no son intercambiables con NSArrays. Debes usarlos intencionalmente.

ACTUALIZACIÓN # 2. Sé que han pasado años desde que esta pregunta fue en vivo, pero acabo de volver a visitarla y me di cuenta de que en este caso específico hay una forma inteligente de solucionarlo. (Desea una NSArray no mutable de una matriz de flotador de estilo C). Puede crear una subclase personalizada de NSArray que ajuste los valores flotantes y solo los convierta en objetos cuando se acceda a ellos a través de las primitivas. Esto puede tener dificultades de rendimiento en algunas esquinas (?), Pero cumple perfectamente con sus requisitos:

@interface FloatProxyArray : NSArray 
{ 
    float * values; 
    NSUInteger count; 
} 
- (id)initWithCArray:(float *)arrayOfFloats count:(int)numberOfValues; 
@end 

.

@implementation FloatProxyArray 
- (id)initWithCArray:(float *)arrayOfFloats count:(int)numberOfValues 
{ 
    if ((self = [super init])) { 
     values = (float *)malloc(numberOfValues * sizeof(float)); 
     if (!values) { 
      [self release]; return nil; 
     } 
     memcpy(values, arrayOfFloats, numberOfValues * sizeof(float)); 
     count = numberOfValues; 
    } 
    return self; 
} 

- (void)dealloc 
{ 
    free(values); 
    [super dealloc] 
} 

- (NSUInteger)count 
{ 
    return count; 
} 

- (id)objectAtIndex:(NSUInteger)index 
{ 
    if (index >= count) { 
     [NSException raise:NSRangeException format:@""]; 
     return nil; 
    } 

    float val = values[index]; 
    return [NSNumber numberWithFloat:val]; 
} 
@end 

(NB Escrito en el editor sin compilar/pruebas.)

+0

Gracias! Eso tiene sentido. –

3

Una optimización que se puede hacer con la NSMutableArray es initWithCapacity lo que evitará la duplicación de la matriz que es la operación caro de la adición .

Fuera de eso, ya que NSArrays y NSMutableArrays esperan objetos, por lo que es difícil de evitar esto.

0

La “mejor” optimización (para velocidad) sería casi seguro que evitar el uso de NSArray por completo, si es posible.

1

¿Qué beneficios de ser un NSArray está buscando obtener?

Parece que usted puede ser mejor con un objeto contenedor de encargo alrededor de la matriz C que responde a lo que los mensajes NSArray que busca llamar. De lo contrario, volverás al punto de la creación de la matriz ... Podrías intentar crear una llamada manualmente a initWithObjects, pero al menos cada flotador debe estar envuelto en un NSNumber, lo que reduciría tu velocidad nuevamente.

Si realmente necesita un NSArray porque algo más desea usar toma objetos NSArray, entonces probablemente sea mejor que subclases NSArray (siguiendo las pautas publicadas por Ben).

Cuestiones relacionadas