2012-01-22 9 views
5

Estoy empezando a escalar la curva de aprendizaje del Objetivo C (usando el libro de programación de Nerd Ranch para iOS).objetivo c "¿Olvidaste anidar alloc e init?"

Sobre la base de lo que he saber de otros idiomas sobre "anidamiento" ejecuciones múltiples dentro de una línea que supuse que pueda alterar:

NSString* descriptionString = [[NSString alloc] initWithFormat:@"%@", possesionName] 

con una versión de dos líneas:

NSString* descriptionString = [NSString alloc]; 
[descriptionString initWithFormat:@"%@", possesionName] 

pero parece que el segundo intento plantea una excepción

2012-01-22 18:25:09.753 RandomPossessions[4183:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -length only defined for abstract class. Define -[NSPlaceholderString length]!' 

¿Podría alguien ayudarme? ¿Y qué estoy haciendo exactamente mal aquí? Muchas gracias por adelantado.

PS. Si esta es la forma en que funcionan los mensajes de Objective C y tienes que hacer alloc e init en una línea, solo házmelo saber - Supuse que esto es solo un conjunto de funciones que pueden ejecutarse dos en una o una tras otra.

+0

hicieron que trató la primera way..both en una línea .. solo quiero saber si funcionó .. – Shubhank

+0

Claro - funciona como encanto con [[ClassName alloc] init] (por lo tanto, dos mensajes anidados uno detrás de otro en una línea) ... pero no estoy seguro de por qué falla la segunda. En lugar de simplemente asumir que "tiene que hacerse de esta manera", me gustaría contar con algunos consejos expertos sobre por qué se hace de esta manera. – Piotr

+1

Esto tiene una respuesta muy interesante que lamentablemente no tengo tiempo ahora para escribir correctamente. (Creo que Abizern está dando vueltas y puede hacerle justicia). La versión ultracorta es que usted puede anidar en general, pero se permite que 'alloc' arroje el objeto que ha pasado y devuelva uno nuevo, por lo que tiene que estar anidado con 'init'. Es una convención que se ha convertido en una regla. –

Respuesta

3

El método alloc asignará memoria para un objeto nuevo. Pero el método init podría descartar esa memoria y devolver un objeto completamente diferente. O puede devolver nil. Es por esto que siempre debe hacer self = [super init] cuando anula un método init.

NSString es una clase que hace este tipo de cosas todo el tiempo.

No estoy exactamente seguro de por qué está ocurriendo la excepción, pero creo que podría ser el código de inyección de ARC entre las dos líneas de código o algo similar. Sea lo que sea, algo está tratando de actuar sobre el objeto asignado que nunca se ha inicializado, y este es un gran problema que puede conducir a todo tipo de problemas. Considérese afortunado de que haya lanzado una excepción, a veces no lo hará.

La clase NSString podría no ser realmente una clase real. Puede contener casi ningún método y casi ninguna variable. Todo lo que tiene es un conjunto de métodos de fábrica para crear objetos de cadena "reales" de alguna otra clase, y esto se hace usando métodos como initWithFormat:. Entonces, por una convención de larga data, alloc/init siempre debe hacerse en una sola declaración y hay un puñado de lugares donde, generalmente por razones de rendimiento, algo dependerá de que se use esta convención.

Básicamente, objetivo-c es un lenguaje en el que no necesita saber exactamente lo que está sucediendo dentro de un objeto. Solo necesita saber qué mensajes se pueden enviar a un objeto y cómo responderá. Cualquier otra cosa es un comportamiento indefinido e incluso si usted aprende cómo funciona, está sujeto a cambios sin previo aviso. A veces, el comportamiento cambiará dependiendo de circunstancias que son completamente ilógicas, por ejemplo, puede esperar que el método de "copia" le proporcione una copia del objeto al que lo envía, y aunque este es el comportamiento predeterminado, hay muchos casos en que en realidad solo devolverá el mismo objeto con banderas de administración de memoria ligeramente diferentes. Esto se debe a que la lógica interna de la clase sabe que devolver el mismo objeto es mucho más rápido y efectivamente idéntico a devolver una copia real.

Mi comprensión es copy enviado a NSString puede devolver un objeto nuevo, o puede devolverlo. Depende de qué subclase de NSString se esté utilizando en realidad, y ni siquiera hay documentación para qué subclases existen, y mucho menos cómo se implementan.Todo lo que necesita saber es que copy devolverá un puntero a un objeto que es perfectamente seguro de tratar como si fuera una copia aunque no lo sea.

En un lenguaje orientado a objetos "adecuado" como Objective-C, los objetos son "cajas negras" que pueden cambiar inteligentemente su comportamiento interno en cualquier momento y por cualquier motivo, pero su comportamiento externo siempre es el mismo.

Con respecto a evitar el anidamiento ... El estilo de codificación para Objective-C a menudo requiere un anidamiento extenso, o escribirás 10 líneas de código cuando solo 1 realmente se necesite. La sintaxis de corchete cuadrado es particularmente adecuada para anidar sin hacer que el código sea complicado.

Como regla general, enciendo la función "Guía de páginas en la columna" de Xcode y la configuro en 120 caracteres. Si la línea de código excede ese ancho, entonces pensaré en dividirla en varias líneas. Pero a menudo es más limpio tener una línea muy larga que tres líneas cortas.

Sé pragmático al respecto. :)

9

Una diferencia importante entre las dos versiones (no son exactamente iguales) es que en la primera versión se utiliza el resultado de initWithFormat para la variable descriptionString, mientras se utiliza el resultado de alloc en el segundo. Si cambia su código a

NSString* descriptionString = [NSString alloc]; 
descriptionString = [descriptionString initWithFormat:@"%@", possesionName] 

todo debería estar bien nuevamente. Se especifica que un objeto devuelto por alloc no se verá como inicializado y funcional hasta que se haya llamado a algún método init y init podría devolver algo más.

+0

derecha - esto funciona. La forma en que lo entiendo es que el objeto asignado con alloc es ignorado por el método initWithFormat [no está inicializando 'mi' objeto sino otro que devuelve inicializado pero lo ignoro]. cuando señalo descriptionString más tarde no está inicializado y es una fuente de mi problema. – Piotr

0

De referencia de la biblioteca de Apple, initWithFormat:

devuelve un objeto NSString inicializado mediante la conversión de los datos dados en caracteres Unicode utilizando una codificación determinada.

Así que usted puede utilizar estas dos líneas de código:

NSString* descriptionString = [NSString alloc]; 
descriptionString = [descriptionString initWithFormat:@"%@", possesionName]; 

Para obtener más información, visite: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/occ/instm/NSString/initWithFormat:

Cuestiones relacionadas