2011-08-17 12 views
7

A veces me gusta organizar elementos IB en NSArray s principalmente para ayudarme a organizar mis elementos. Muy a menudo, las diferentes clases de objetos forman el mismo conjunto entre sí. Si bien esto es una forma conveniente de organización, me parece que no puede envolver mi cabeza alrededor de eso que si tengo una matriz de esta manera:for loops - ¿Tipo de objeto descartado?

NSArray *array = [NSArray arrayWithObjects:((UITextField *)textField), ((UISegmentedController *)segmentedController), nil]; 

¿Por qué me sale "no responde al selector" mensajes cuando poner un bucle for así:

for (UITextField *text in array) { 
    [text setText:@""]; 
} 

El bucle for parece estar superado objetos que no son de la clase UITextField.

¿Cuál es el punto de declarar la clase del objeto si todos los objetos en la matriz especificada se pasan a través del ciclo?

EDITAR Sólo como referencia, así es como yo estoy manejando a partir de ahora:

for (id *object in array) { 
    if ([object isMemberOfClass:[UITextField class]]) { 
     foo(); 
    } else if ([object isMemberOfClass:[UISegmentedController class]) { 
     bar(); 
    } 
} 
+0

'id' ya es un tipo de puntero. 99.9% del tiempo, quiere usar el tipo 'id' simple, no un puntero a 'id *'. –

Respuesta

10

Al hacer

for (UITextField *text in... 

los punteros a objetos de la matriz se convierten a UITextField * Tipo - por lo que si el objeto no es en realidad un UITextField, todo tipo de cosas extrañas pueden suceder si se intenta llamar UITextField métodos.

Así que en lugar de utilizar el tipo de identificador (no * es necesario, por cierto):

for (id obj in array) 

A continuación, comprobar el tipo como lo hace y llamar a los métodos apropiados. O bien, filtrar la matriz para obtener sólo los objetos de un tipo determinado, y luego ir a pesar de ese tipo solamente:

for (UITextField* text in [array filteredArrayUsingPredicate:...]) 

Editar: aquí es cómo construir predicados de filtro de clase:

Is it possible to filter an NSArray by class?

+0

Los objetos no se lanzan a tipos nuevos, los punteros sí. El tipo del puntero no importa un ápice cuando se trata de enviar mensajes. Podría enviar '-appendString:' a un objeto usando un puntero de tipo 'NSWindow *' si así lo desea, y funcionará bien siempre que el puntero realmente apunte a una instancia de NSMutableString. (Puede recibir una advertencia de compilación, pero funcionará.) Sin embargo, si el puntero apunta a una ventana, obtendrá un error en el tiempo de ejecución a menos que tome medidas para evitarlo. – Caleb

+0

Tiene razón, por supuesto, modifiqué mi respuesta en consecuencia. – SVD

+0

la parte que necesita edición es "si el objeto no es realmente un UITextField, pueden ocurrir todo tipo de cosas extrañas ...". Si el objeto no es realmente un UITextField, obtendrá una excepción de selector no implementado. – Caleb

5

¿Cuál es el punto de declarar la clase del objeto si se pasan todos los objetos de la matriz especificada a través del bucle?

El nombre de la clase está ahí para que el compilador sepa lo que debe esperar encontrar. Esto le permite intentar averiguar qué métodos debe esperar que llame y cómo puede tratar el objeto. Es la misma idea que pasar un int a un método que toma float. El método no ignorará los enteros, suponiendo que está pasando el tipo correcto. Le está dando a este constructo un poco más de crédito de lo debido:

for (UITextField *text in array) 

Simplemente no tiene esa funcionalidad. Cómo lo está manejando ahora es la forma correcta.

0

¿Seguro no obtiene un error cuando ejecuta ese código? El mensaje "no responde al selector" es un error de tiempo de ejecución, no un error de tiempo de compilación.El compilador no tiene idea de si los objetos de la matriz implementan -setText:, pero ciertamente debería obtener un error cuando realmente envíe ese mensaje a una instancia de UISegmentedControl.

Otra posibilidad es que tenga una clase llamada UISegmentedController que tiene un método -setText:. El nombre de la clase que implementa el widget de interfaz de usuario de barra de gráficos de varias partes es UISegmentedControl. Entonces, o el código que está mostrando no es un código real o probado, o tiene una clase que no conocemos.