2011-09-11 7 views
8

tengo 2 nuevas preguntas:son NSStrings almacenados en el montón o en la pila y lo que es una buena manera de inicializar una

1) Considerar esta línea:

NSString *myString = [[NSString alloc] initWithString: @"Value"]; 

Había dos cosas que me aprendido, pero me gustaría la confirmación: Como me enteré, el mensaje "alloc" indica que la instancia de NSString se almacenará en la memoria "Heap". Entendí también que las variables primitivas como "caracteres" se almacenan en la memoria "apilar".

¿Quiere decir esto que:

  • la instancia de NSString se almacena en la memoria de pila;
  • Y que este objeto tiene un puntero iVar (cuando se llamó al método initWithString) a la cadena "Valor" de "caracteres" primitivos, que residen en la memoria de la pila? ¿Cómo funciona esto en realidad?

La segunda pregunta está directamente relacionado y hace que para mí un dilema personal (probablemente porque me falta un punto): 2) ¿Cuál de los dos enfoques le consulte y por qué ?:

NSString *myString = [[NSString alloc] initWithString: @"Value"]; 
NSString *myString = @"Value"; 

Si mi primera pregunta es confirmada, ambos enfoques deberían "al final" apuntar a los caracteres que están almacenados en la memoria de la pila. Por lo tanto, realmente no veo el propósito de usar la primera opción y molestarme con el conteo retenido.

Respuesta

13

Respuesta corta: En este caso, ambas líneas tienen el mismo resultado Está bien asignar la constante de cadena directamente al myString.

Respuesta larga:

Es cierto que los objetos Objective-C se asignan en el montón. Sin embargo, no es cierto que los valores "primitivos" siempre se almacenen en la pila. Las variables locales se almacenan en la pila, ya sean primitivas o no. (Puede, por ejemplo, declarar una variable local que sea una estructura, que no se considera primitiva). Puede almacenar valores primitivos en el montón, pero la única manera de acceder a ellos en ese caso es a través de un puntero. Por ejemplo:

int *someInt = malloc(sizeof(int)); // allocate a block of memory to hold an int 
*someInt = 42;      // store data in that memory 

La razón por la que siempre punteros utilizar para hacer referencia a los objetos Objective-C es que los objetos siempre se asignan en el montón. Si desea almacenar algo en la pila, el compilador necesita saber su tamaño. En Objective-C, el tamaño de un objeto no se conoce hasta que el programa realmente se está ejecutando.

Así que, de vuelta a sus cadenas. Intente ejecutar las dos líneas siguientes:

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

Si se rompe después de la segunda línea, usted encontrará que foo y bar contienen la misma dirección; es decir, apuntan al mismo objeto. Debido a que los objetos NSString son inmutables, crear uno con una cadena constante simplemente devuelve un puntero a esa constante.

¿Por qué hay incluso un -initWithString: en NSString si eso es todo lo que hace? NSString es un "clúster de clase", lo que quiere decir que NSString es la interfaz pública para varias clases internas diferentes. Si pasa un NSString * que no es una constante en -initWithString:, el objeto que obtenga puede ser una instancia de una clase diferente a la que obtiene cuando usa la constante. Como un clúster de clase, NSString oculta una gran cantidad de detalles de implementación para que pueda obtener un buen rendimiento para diferentes tipos de cadenas sin tener que preocuparse por cómo funciona.

4

NSString s son interesantes porque hasta hace poco eran el único tipo de objeto Objective-C que se podía proporcionar como un literal. Los objetos de bloque añadidos en iOS 4 y OS X 10.6 son la otra adición reciente de la que soy consciente, pero tienen sus propias reglas particulares, así que lo menciono solo por completitud.

C primitivas se pueden almacenar en el montón o en la pila. Por ejemplo:

- (void)someMethod 
{ 
    int i = 3; // i is on the stack 
} 

- (void)someOtherMethod 
{ 
    int *i = (int *)malloc(sizeof(int)); // i now points to an 'int' on the heap 
} 

La mayoría de los objetos de Objective-C solo se pueden almacenar en el montón. Tiene toda la razón al decir que alloc proporciona una nueva copia de un objeto en el montón, y el resultado de su llamada myString será tener un puntero a un NSString en el montón.

Sin embargo, la sintaxis @"" es una abreviatura para crear un objeto. @"Value" en realidad crea un objeto literal. Entonces, por ejemplo, puede hacer:

NSLog(@"%@", [@"Value" substringFromIndex:1]); 

Y la salida sería 'alue'. Puede enviar el mensaje substringFromIndex: al @"Value" porque es un objeto literal.

Exactamente lo que NSString hace con initWithString: es una implementación específica, pero puede estar seguro de que tomará una copia de lo señalado si es necesario. De lo contrario se vería extraño comportamiento si se hizo algo como esto:

NSMutableString *mutableString = [NSMutableString stringWithString:@"String"]; 
NSString *immutableString = [NSString stringWithString:mutableString]; 

[mutableString appendString:@" + hat"]; 

// immutableString would now have mutated if it was simply 
// keeping a reference to the string passed in 

lo tanto, no necesita preocuparse acerca de la vida útil de cualquier cosa que pase a ella. Es el trabajo de NSString lidiar con eso.

En la práctica, los literales de objeto NSString en realidad nunca caducan, por lo que el punto es un poco discutible. Sin embargo, si hubiera usado initWithUTF8String: o alguna otra cosa que tomara un literal C y ese literal C estuviese en la pila, aún no tendría nada de qué preocuparse porque NSString se encargaría de ello.

En respuesta a su segunda pregunta, preferiría la segunda versión porque es más corta y, por lo tanto, demuestra más claramente lo que pretende hacer. Hay algunos beneficios de rendimiento teórico para este último, especialmente si utiliza el mismo literal en varios lugares, pero son tan increíblemente insignificantes que no valdría la pena considerarlos hoy en día.

Cuestiones relacionadas