2011-10-17 11 views
5

Suponiendo que "someData" es un NSMutableData que contiene algunos bytes de datos.Comprender initWithBytes para un NSString

si escribo lo siguiente:

NSString *someString = [NSString string]; 
[someString initWithBytes:[someData mutableBytes] length:[someData length] encoding:NSUTF8StringEncoding]; 

La segunda línea me da un "selector de reconocido enviado a la instancia" error

Pero si escribo:

NSString *someString=[[NSString alloc] initWithBytes:[someData mutableBytes] length:[someData length] encoding:NSUTF8StringEncoding]; 

entonces funciona . ¿Hay alguna razón por la cual la forma anterior no funciona? ¿Se puede hacer sin "alloc", (creando someString de antemano?)

Gracias.

+1

Debe leer los conceptos básicos de "[El lenguaje de programación Objective-C] (http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Introduction/introObjectiveC.html)". – sidyll

+0

Su pregunta debe ser acerca de 'alloc' &' init' en lugar de este método 'NSString'. – Richard

Respuesta

4

La razón es que el objeto devuelto por [NSString string] no responde al selector -initWithBytes:length:encoding:. Esto se debe a que los NSString son inmutables; no se pueden cambiar una vez creados. El método -string toma ventaja de esto y solo le da una referencia a una cadena constante (creada en tiempo de compilación) que está vacía.

No solo eso, sino que NSString es un clúster de clase. Esto significa que cuando solicite un NSString, es posible que obtenga una instancia de una de sus subclases. Supongo que está obteniendo una subclase que tiene -initWithBytes:length:encoding: anulado para lanzar una excepción porque no tiene sentido enviar un método init a una cadena constante creada en tiempo de compilación.

En su segundo caso, está creando un nuevo NSString en tiempo de ejecución y luego le envía un mensaje de inicio. Esto está perfectamente bien. Tenga en cuenta que, dado que es un clúster de clase, la cadena devuelta por el método init podría no ser la misma que la creada por -alloc.

+0

Creo que veo. El primer caso crea un NSString en tiempo de compilación. Una vez creado, no puede ser reinicializado. El último caso crea un objeto de cadena en tiempo de ejecución y lo inicializa en la misma línea. Sin embargo, reemplazar la segunda línea en el primer caso con [someString init] no causa un error. Tal vez es el problema del grupo de clase. – Dave

3

La primera forma crea una cadena vacía, autorrellenada que ya se ha inicializado y luego intenta inicializar la cadena por segunda vez. La segunda forma asigna memoria, luego la inicializa apropiadamente. Tenga en cuenta que la segunda forma no libera automáticamente la cadena creada, por lo que el alcance de la llamada sigue siendo responsable. Si quisieras, podrías envolver la segunda manera en un método de conveniencia en una categoría de NSString para conseguir algo más similar a la primera:

@interface NSString (stringWithBytes) 

+ (NSString*)stringWithBytes:(const void *)bytes length:(NSUInteger)length encoding:(NSStringEncoding)encoding; 

@end 

@implementation NSString (stringWithBytes) 

+ (NSString*)stringWithBytes:(const void *)bytes length:(NSUInteger)length encoding:(NSStringEncoding)encoding { 
    NSString * aString = [[NSString alloc] initWithBytes:bytes length:length encoding:encoding]; 
    return [aString autorelease]; 
} 

@end 
+1

¿No deberían ser métodos de clase? – jrturton

+0

Ah, buena captura. Voy a editar para que coincida. Escribir código directamente en lugar de pegar desde Xcode siempre parece provocar la pérdida de algo. – RPeck

+1

Escribo muchas respuestas en mi _phone_. Es un milagro que tenga cualquier representante. – jrturton