2009-07-19 7 views
52

He estado jugando con el desarrollo de iPhone por un tiempo, y aunque te parece un poco incómodo cuando eres un desarrollador de .NET "hard core", no es tan malo una vez que te acostumbras.¿Está bien usar malloc()/free() "clásico" en aplicaciones Objective-C/iPhone?

En cada libro que leí sobre Objective-C, solo se habla de retención/liberación (recuento de referencias) para la gestión de la memoria. Como desarrollador de C/C++ antiguo, parece extraño que asignar la forma "normal", utilizando malloc() y libre() solo se menciona en algunas notas a pie de página.

Sé que malloc() y free() funcionan en Objective-C, pero tengo curiosidad si es una práctica común o no. Después de todo, si quiero asignar una matriz de 100 enteros, parece que esta es la manera más eficiente de hacerlo:

int *array = malloc(sizeof(int) * 100); 

memset(array,0,sizeof(int) * 100); 

// use the array 

free(array); 

Es este hecho la mejor manera, o debería evitar una gestión sencilla de memoria C?

Respuesta

77

Hay un contenedor Objective-C alrededor de la memoria en bruto que me gusta usar mucho para tareas similares: NSMutableData. Tiene el beneficio de otorgarle retención/liberación de propiedad además de que puede hacer crecer la matriz fácilmente (sin tener que hacer el realloc usted mismo).

Su código se vería así:

NSMutableData* data = [NSMutableData dataWithLength:sizeof(int) * 100]; 
int* array = [data mutableBytes]; 
// memory is already zeroed 

// use the array 

// decide later that we need more space: 
[data setLength:sizeof(int) * 200]; 
array = [data mutableBytes]; // re-fetch pointer in case memory needed to be copied 

// no need to free 
// (it's done when the autoreleased object is deallocated) 
+0

Me gusta esta respuesta @Nikolai Ruhe. Estaba usando una matriz ed "malloc" como propiedad. Tenía 3 objetos de esta clase, y "liberé" la matriz en dealloc. Sin embargo, después de liberar el primer objeto, obtuve un error "malloc: *** error para el objeto 0x70a60: el puntero se liberó no se asignó" al liberar el segundo? Parece que el malloc se hizo en "nivel de clase", en lugar de "nivel de objeto". El cambio a su solución hizo que esto desapareciera, pero el "comportamiento" de los objetos también cambió. Todavía no estoy seguro por qué. – iPadDeveloper2011

+0

OK, probé esto y, para mi horror, finalmente descubrí que mi "matriz" se llenaba con bits aleatorios. Supongo que los "datos" subyacentes se lanzaron automáticamente antes de que terminara la matriz. Poner un "retener" en los datos solucionó ese problema, pero ahora debo mantener una referencia al objeto "datos", haciendo que esta solución sea menos atractiva. – iPadDeveloper2011

+0

OK @Nikolai Ruhe, esta es una respuesta realmente horrible que desperdició casi todo mi día. Incluso si 'data' es una" variable de objeto ", parece que se libera automáticamente, lo que permite que' array' se llene. La única forma de obtener un comportamiento similar a un malloc parece ser '[retención de datos];', lo que hace que esta sea una respuesta muy engañosa. Una mejor forma de usar 'NSMutableData' sería comenzar con' NSMutableData * data = [[NSMutableData alloc] initWithLength: sizeof (int) * 100]; ' – iPadDeveloper2011

2

Está perfectamente bien utilizar malloc y libre de hacer su propia gestión de memoria. En realidad, allocWithZone: de NSObject usa malloc para obtener la memoria.

+1

Es técnicamente calloc, pero sí. =) –

+6

En realidad, es técnicamente 'NSAllocateObject()'. Lo que sucede a continuación es más complicado. En ObjC2 con GC habilitado, 'NSAllocateObject()' llama a 'objc_allocate_object()'. En ObjC2 sin GC o ObjC <2, 'NSAllocateObject()' llama a 'class_createInstanceFromZone()', que a su vez llama 'malloc_zone_calloc()', que, como su nombre lo indica, es lógicamente equivalente a 'calloc () '. Un 'calloc()' con un 'count' de' 1' es por definición indigistqushable de una asignación obtenida por 'malloc' del mismo' size' que ha tenido su 'space initialized to all bit zero' (C99 7.20. 3.1.2). – johne

+1

entonces ... ¿qué dijo Dave? – typeoneerror

5

Por supuesto, usted puede utilizar estas funciones, debido a Objective-C no es más que un superconjunto de C. Sin embargo, es bastante infrecuente que hacer este tipo de cosas, ya que Objective-C contiene los objetos y las maneras de hacer esto más fácil.

Después de todo, se podría escribir el código anterior como:

NSMutableArray *array = [[NSMutableArray alloc] init]; 

//Use the array, adding objects when need be 

[array release]; 

A pesar de que tendría que crear NSNumber objetos para almacenar los int s (desde NSArray no permite tipos no-objeto que se añadirán) , generalmente es más común usar objetos, porque es más fácil mover datos, y las clases de matriz se integran más comúnmente con otras clases de Cocoa, y la administración de memoria es generalmente más directa que la administración de memoria C estándar.

Además, si comienza a agregar o eliminar objetos de la matriz, los objetos de la matriz Cocoa lo hacen mucho más fácil.

+2

Esto parece exagerado si necesita una matriz simple de enteros. Especialmente la necesidad de crear objetos NSNumber me parece tan ineficiente. ¿Qué ocurre si quiero asignar una matriz de 100.000 booleanos? –

+0

Tal vez, puede haber una ligera sobrecarga en comparación con el uso de matrices simples de números enteros. Pero ciertamente son más comúnmente utilizados que el uso de la administración de memoria C. Y si está asignando una matriz de 100.000 booleanos, puede haber una forma mejor de hacerlo que la forma en que actualmente lo está implementando (a menos que sea un escenario hipotético). –

+1

Esto es especialmente exagerado si se trata de objetos realmente simples. Por ejemplo, si construyes MineSweeper para el iPhone, es * órdenes de magnitud * más rápido tener un cuadrado como una estructura y malloc una serie de estructuras que para crear los cuadrados como objetos y ponerlos en un NSArray. Además, usará bastante menos memoria. –

47

Está perfectamente bien - Objective-C es un superconjunto estricto de C, por lo que si quieres escribir C simple, no hay nada que te lo impida. En muchos casos, es ventajoso usar malloc y free para evitar la sobrecarga del tiempo de ejecución de Objective-C.

Por ejemplo, si necesita asignar dinámicamente una matriz de un número desconocido de números enteros, a menudo es más simple y más fácil:

int *array = malloc(N * sizeof(int)); // check for NULL return value! 
// use array[0]..array[N-1] 
... 
free(array); 

Versus:

NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:N]; 
// use NSMutableArray methods to do stuff with array; must use NSNumbers instead 
// of plain ints, which adds more overhead 
... 
[array release]; 

yo estaba trabajando en una palabra juego para el iPhone, y tuvimos que cargar un diccionario multi-megabyte de palabras válidas. La lista de palabras se cargó en una única matriz char asignada con malloc(), con algunas optimizaciones inteligentes para reducir el tamaño de la memoria aún más. Obviamente para algo como esto, la sobrecarga de usar un NSArray es completamente impracticable en el iPhone limitado. No sé exactamente cuál es la sobrecarga, pero ciertamente es más de un byte por personaje.

+6

RE: 'superconjunto estricto'. Si bien estoy personalmente (muy) de acuerdo con usted, dado que estamos discutiendo el desarrollo de Apple/iPhone, esta afirmación no es técnicamente cierta. Apple lo define así: 'La sintaxis Objective-C es un superconjunto de la sintaxis GNU C/C++'. El superconjunto estricto tiene un significado muy específico, con el uso no calificado de superconjunto como el menor de los dos (piense "se comporta como" vs. "exactamente como"). El calificador de 'sintaxis' lo restringe aún más hasta el punto en que es casi inútil, limitando efectivamente la obligación de la manzana al anexo A de la especificación C99, es decir, 16 páginas de un mínimo de 552 en la norma. – johne

+0

He tenido una serie de problemas al utilizar malloc/free en Objective C. Ver mi comentario a la respuesta de Nikolai. Aparte de eso, he tenido problemas para asignar punteros (copiar) a arreglos mal colocados para compartir la matriz mal colocada entre los objetos. – iPadDeveloper2011

+0

Si bien es cierto que puede usar malloc() y free(), puede evitar la mayor parte de la sobrecarga del tiempo de ejecución usando un NSMutableData de la longitud adecuada en su lugar. –

3

Si se trata de tipos de C estándar, no es menos común o "OK" que en C.Así es como se hace en C, que es una parte de Objective-C.

Tampoco es inusual escribir algún tipo de envoltorio de objetos alrededor de estas cosas para armonizarlo con el resto de Cocoa (KVO, gestión de memoria, etc.). Por lo tanto, puede crear una clase IntArray que haga el malloc entre bastidores para que pueda retenerlo y liberarlo según sea necesario. Tenga en cuenta que esto no es estrictamente necesario; puede ser útil si ese tipo de estructura es una parte importante de su programa.

Cuestiones relacionadas