2009-09-28 7 views
8

Según tengo entendido, ambos crean un NSMutableString, solo el primero es propiedad del sistema y el segundo pertenece a mí (es decir, necesito liberarlo). ¿Hay alguna razón particular por la que deba usar uno u otro, a primera vista parece más fácil usar el primero? También es el primero mejor, ya que le da al compilador una sensación de tamaño?¿Está definiendo NSMutableString?

NSMutableString *newPath = [NSMutableString stringWithCapacity:42]; 

O

NSMutableString *newPath = [[NSMutableString alloc] init]; 

EDITAR ... También

lo vea mucha unas declaraciones escritas en dos líneas (es decir)

NSMutableString *newPath; 
newPath = [NSMutableString stringWithCapacity:42]; 

personalmente prefiero el uno delineador, ¿es este otro ejemplo de estilo personal?

Respuesta

16
NSMutableString *newPath = [NSMutableString stringWithCapacity:42]; 

O

NSMutableString *newPath = [[NSMutableString alloc] init]; 

¿Hay alguna razón en particular por la que debe utilizar uno o el otro, en la cara de ella parece más fácil de usar la primera?

Sí. Siempre haga una liberación automática inmediatamente a menos que tenga una razón específica para no hacerlo.

La primera razón es que es muy fácil olvidarse de escribir el mensaje release. Si liberas el objeto automáticamente en la misma instrucción donde lo creas (como en el [[[… alloc] init] autorelease]), es mucho más difícil olvidarlo y mucho más obvio cuando lo haces. Los métodos de fábrica de conveniencia (como stringWithCapacity:) liberan automáticamente el objeto por usted, por lo que al igual que cuando lo suelta automáticamente, no tiene que preocuparse de soltarlo más tarde.

En segundo lugar, incluso si recuerda escribir el mensaje release por separado, es fácil no pegarle. Dos formas son los primeros resultados:

NSString *str = [[NSString alloc] initWithString:@"foo"]; 

BOOL success = [str writeToFile:path atomically:NO]; 
if (!success) 
    return; 

[str release]; 

y lanzados o propagadas excepciones:

NSString *str = [[NSString alloc] initWithString:@"foo"]; 

//Throws NSRangeException if str is not in the array or is only in the array as the last object 
NSString *otherStr = [myArray objectAtIndex:[myArray indexOfObject:str] + 1]; 

[str release]; 

La “razón específica para no” es en general de que tiene un bucle estrecho que crea una gran cantidad de objetos, en el cual En caso de que desee, puede administrar manualmente tantos objetos en el bucle como sea posible para mantener su cuenta atrás. Sin embargo, solo haga esto si tiene evidencia de que este es su problema (ya sean números duros de Shark, números duros de Instruments o que su sistema entre en el infierno de paginación siempre que ese bucle se ejecute lo suficiente).

Otras soluciones, posiblemente mejores, incluyen dividir el bucle en dos bucles anidados (el externo para crear y drenar un grupo de autorrelease para el bucle interno) y cambiar a NSOperation. (Sin embargo, asegúrese de que establece un límite en el número de operaciones se ejecuta la cola en un momento; de lo contrario, you may make it even easier to go into paging hell.)

También es el primer mejor, ya que da el compilador una sensación de tamaño?

Es mejor, pero no por esa razón.

Para el compilador, es simplemente otro mensaje de clase. El compilador no sabe ni le importa lo que hace; por todo lo que sabe y le importa, stringWithCapacity: es el mensaje para reproducir una canción para el usuario.

Proporciona NSMutableString una sugerencia de tamaño: la clase sabrá cuánto almacenamiento de caracteres puede querer asignar inicialmente. Cualquier beneficio que obtenga de esto es probablemente pequeño (al menos en Mac), pero si tiene la información a mano, ¿por qué no usarla? Por el contrario, no me desviaría de mi camino para calcularlo.

Veo mucho a las declaraciones por escrito en dos líneas (es decir)

NSMutableString *newPath; 
newPath = [NSMutableString stringWithCapacity:42]; 

Personalmente prefiero el de una sola línea, es sólo otro ejemplo de estilo personal?

Sí. Sin embargo, existe una cierta cantidad de riesgo al dejar una variable sin inicializar. Definitivamente active la configuración de compilación "Ejecutar analizador estático" si decide hacerse un hábito de esto.

+4

+1, excepto que no estoy de acuerdo con "Liberar automáticamente siempre a menos que tenga una razón específica para no hacerlo". Su justificación para esto ("es muy fácil olvidarse de escribir el mensaje de 'liberación'") no es tan relevante ahora que el analizador estático detectará fácilmente este error. Personalmente, evito los objetos liberados automáticamente, solo para evitar el desorden automático de la agrupación de autorrelease y el golpe que puede venir de agotar un grupo de autorrelease muy grande (que sí, me he dado cuenta). Generalmente prefiero amortizar el costo de la desasignación ejecutándola tan pronto como sea razonablemente posible. –

+0

El analizador estático puede tardar cierto tiempo en ejecutarse en algún código fuente, por lo que es posible que no lo desee todo el tiempo. Y la mayor parte del costo de drenar un grupo de autorrelease es liberar los objetos, lo que tienes que hacer de todos modos. La única razón por la que se destaca es porque los libera a todos (o a algunos miles) a la vez en vez de unos pocos milisegundos. –

+0

NO suelte ni suelte de nuevo hasta el final del método. Cualquier mensaje después del -autorelease puede potencialmente vaciar el grupo de autorrelease. Si devuelve un objeto liberado automáticamente, no desea ninguna posibilidad de que se destruya antes de que la persona que llama lo obtenga. – NSResponder

4

El primero no es necesariamente para el compilador, sino una sugerencia para la cadena sobre cómo podría optimizar el almacenamiento de sus datos. Esto es más útil para NSDictionary/NSArray/NSSet, que have the ability to internally change their implementations depending on the size of their data set.

Aparte de eso, estás en lo cierto: la única diferencia es una cuestión de propiedad. Casi nunca utilizo los métodos WithCapacity, y simplemente uso [NSMutableString string] o [NSMutableArray array], pero IMO, es realmente solo una cuestión de estilo y no ganarás ni perderé nada al usar uno sobre el otro.

+0

¿Personalmente usted iría por el alloc y haría el lanzamiento usted mismo? – fuzzygoat

+0

@fuzzygoat - Depende. Puedo usar uno u otro en función de las limitaciones de memoria, ya sea que esté escribiendo código de acceso rápido, etc. –

1

Responde preguntas válidas. Realmente depende de lo que estés haciendo, pero para las aplicaciones generales de iPhone, yo diría que solo utilizas la primera. Esto se limpiará automáticamente cuando el recuento de referencias llegue a 0 y no tendrá que preocuparse por ello.

Utilice la segunda cuando realmente tenga una buena razón para administrar la memoria de la cuerda usted mismo. Por ejemplo, si quiere estar seguro de cuándo se debe limpiar la cadena o si espera que la memoria sea mínima en un momento determinado.

Yo diría que como regla general use la segunda cuando tenga un buen motivo para hacerlo.

2

La primera es una cadena autorrellenada. Esto será liberado por el sistema en un punto apropiado. Se agrega al grupo de autorrelease y el sistema manejará la memoria. Una vez que está fuera del alcance, no puede afirmar que será válido. Este tipo es útil si solo tiene alcance dentro de su método, y también para devolver los valores de los métodos.

El segundo se retiene, por lo que tendrá un recuento de referencia de 1 y no se agregará al grupo de liberación automática. Usted es responsable de liberarlo y liberar la memoria. Utilice este método si desea controlar el alcance del objeto. Utilizado para variables miembro, etc.

Creo que la inicialización de 2 líneas es solo estilo, pero no usaría la variación de 2 líneas mientras define la variable sin asignarle un valor, aunque esté en la línea siguiente . Supongo que este tipo de espejos declara/inicializa la variable miembro, pero personalmente no me gusta mucho.

1

¡Tiene razón en todos sus puntos!

No estoy seguro de cuán grande es la diferencia que hace la sugerencia de tamaño/capacidad, pero más información debería permitir que el tiempo de ejecución tome mejores decisiones.

¿Por qué usar un estilo sobre el otro?Bueno, ¿cuándo se lanzan los objetos liberados automáticamente? Hay dos razones no obvias por las que podría importar. Primero, cuando un método usa mucha memoria, puede liberarlo inmediatamente. (También podría usar un grupo local de autorrelease). En segundo lugar, creo que el uso de la liberación automática puede ocultar fugas de memoria y hacer que la depuración de algún código sea más difícil. Su millaje puede variar según la edad y la calidad del código.

Cuando comencé a desarrollar aplicaciones para iPhone usé objetos liberados automáticamente todo el tiempo. Fue conveniente porque no entendía completamente cómo funcionaba todo y usualmente hacía lo correcto. Estos días tiendo a equivocarme en el lado de la desasignación manual de memoria. Realmente no es tan difícil cuando realmente entiendes cómo funciona el recuento de referencias y fuerza el problema de inmediato cuando no lo haces.

+0

"En segundo lugar, creo que el uso de la liberación automática puede ocultar pérdidas de memoria y hacer que la depuración sea más difícil". Encuentro lo contrario. Si no liberas algo inmediatamente (como en '[[[[alloc] init] liberación automática]'), es ** muy ** fácil olvidar el mensaje 'liberación' más tarde. –

+0

Además, incluso si recuerda escribir el mensaje 'release', es fácil no pegarle. Dos formas son las devoluciones anticipadas ('if (! Success) return NO;') y excepciones lanzadas o propagadas. –

+0

Lo expresé deliberadamente como "lo encuentro" ya que aprecio que esto sea una preferencia personal. Cometí menos errores de esta manera, ya que me obliga a considerar el ciclo de vida de una variable cuando escribo el código. Su kilometraje, como dije, puede variar. –

0

Si está seguro de cuánto tiempo necesitará una cadena, siga adelante y use el método -initWithCapacity :. Cuando excedes el almacenamiento de una cuerda, se reasigna y se copia, lo que no es una operación barata.

Cuestiones relacionadas