2009-07-30 7 views
7

Tengo una función que deseo operar en dos objetos personalizados diferentes. Mi primer pensamiento fue aceptar el argumento como un (id) y operar el objeto id. Sin embargo, no puedo entender cómo hacerlo.Usando (id) en Objective-C

Ambas clases (decir las manzanas y naranjas) tienen variables de interfaz:

NSDecimalNumber *count; 

que quiero hacer algo similar a esto:

-(NSDecimalNumber*)addCount:(id)addObject{ 

    return [count decimalNumberByAdding:addObject.count]; 
} 

Me parece que no puede averiguar la sintaxis para hacer que eso suceda ¿Es este el enfoque adecuado, o sería mejor crear una subclase (por ejemplo, una clase de fruta) y operar en la clase de padres?

-(NSDecimalNumber*)addCount:(Fruit*)addFruit{ 

    return [count decimalNumberByAdding:addFruit.count]; 
} 

Respuesta

12

Si bien puede enviar un mensaje a cualquier objeto (id), los solicitantes de propiedad requieren que el compilador tenga en cuenta el tipo con el que está tratando, esto es porque los accesadores de propiedad son azúcares sintácticos para llamar a métodos getter y setter específicos.

usted tiene un par de maneras de trabajar alrededor de este:

  1. lugar de acceder a la propiedad Count, llame a los correspondientes [getCount] métodos.

  2. Si las diferentes clases tienen diferentes versiones de este método, se puede utilizar una verificación de tipos en tiempo de ejecución:

  3. proporcionar una clase base para los dos tipos de modo que se puede pasar en algo más específico que (id).

  4. Define e implementa un protocolo que implementen ambos objetos que define una propiedad de conteo (o método).

Ejemplo de un cheque de tipo dinámico:

if([object isKindOfClass:[Apple Class]) 
    // call one overload of getCount 
else if([object isKindOfClass:[Orange Class]) 
    // call another overload of getCount 

Personalmente, estoy a favor de tipado fuerte en mi código, ya que hace que sea más fácil de entender la intención. También le permite al IDE soportar su esfuerzo de codificación con funciones de intellisense, análisis estático y refactorización. Entonces, en su caso, usaría el # 3 o el # 4 como enfoque, dependiendo de si la herencia es realmente apropiada para el problema.

+1

Soy fan de mecanografía fuerte yo mismo (fui con el número 4 de FYI). Muchas gracias por la informacion; ¡Esto es exactamente lo que estaba buscando! –

+0

Si realmente necesita escribir fuerte, puede pasar un mejor momento con un lenguaje estático como C++. Es una pena que las propiedades se comporten de esta manera asimétrica. Como mínimo, debe haber un indicador de compilación para permitir el comportamiento de compilación simétrica entre la sintaxis de la propiedad y la sintaxis del método del receptor. – ctpenrose

+0

@ctpenrose Obj-C puede ser tipado tan estáticamente como el siguiente idioma si así lo desea. – kubi

0

Has enviado el mensaje para que cuentes, ¿cuánto es? id es un puntero a cualquier tipo de objeto. Si espera que el objeto tenga una propiedad de conteo, solo debería poder pasar una matriz (o alguna otra restricción de tipo).

-(NSDecimalNumber*)addCount:(NSArray*) Object{ 

return [count decimalNumberByAdding: [Object count]]; 

} 
0

Como yo lo entiendo, id no tiene ningún métodos o variables asociadas con ella, ya que es un puntero genérico que no se refiere a ninguna clase específica. This page tiene alguna buena información sobre los ids si te desplazas un poco hacia abajo.

anObject esto no tendrá una variable count, por lo que su primer intento no funcionará. Crear una clase base y usar eso como un parámetro para el método me parece la mejor idea.

8

Debe intentar no acceder a variables de instancia de otra clase.

En Objective-C es suficiente que los dos objetos respondan al mismo selector (digamos count), pero eso le daría una advertencia del compilador.

Hay dos maneras de eliminar esta advertencia: ya sea subclasando desde una clase común Fruit o haciendo que sus dos clases cumplan con un protocolo. Me quedo con el protocolo:

@protocol FruitProtocol 

- (NSDecimalNumber *)count; 

@end 

@interface Orange : NSObject<FruitProtocol> 
@end 

@interface Apple : NSObject<FruitProtocol> 
@end 

A continuación, el método puede tener este aspecto:

-(NSDecimalNumber*)addCount:(id<FruitProtocol>)addFruit { 
    return [count decimalNumberByAdding:[addFruit count]]; 
} 

Aquí está diciendo que su addCount espera que cualquier objeto que cumpla con el protocolo FruitProtocol, y por lo tanto puede responder al selector count, por lo que el compilador lo aceptará.

+0

wrt/"No puede acceder a variables de instancia de otra clase". Ciertamente puedes. Si escribe estáticamente un objeto, es decir, 'objeto MYObject * ;, entonces puede acceder a sus variables de instancia desde cualquier clase con el operador' -> '. Por ejemplo, suponiendo que 'MYObject' tenía' 'int' ivar llamado' count', podría usar 'int myCount = object-> count;' para acceder a él. Las protecciones proporcionadas por '@ private', etc., son solo cosméticas, incluso en ObjC2. – johne

+0

¡Esto es genial! Su muestra de código me facilitó la implementación sin más excavaciones. ¡Muchas gracias! –

+0

Tienes razón johne, lo cambiaré a "no deberías". Gracias – pgb

1

El problema es que está intentando acceder a 'addFruit.count'. La sintaxis de puntos es solo para propiedades declaradas con @property (o para estructuras). Si lo cambia a

[addFruit count] 

y añadir

-(NSDecimalNumber*)count 
{ 
    return [[count retain] autorelease]; 
} 

a cada clase, entonces sería trabajar. Sin embargo, notará que recibirá una advertencia diciendo que 'id' puede no responder al mensaje de 'conteo', y a menos que pueda estar absolutamente seguro de que los elementos enviados a este método implementan un método de 'conteo', este es un enfoque problemático .

Estoy de acuerdo con el enfoque de pgb. Debe definir un protocolo y declarar ambas clases para implementar ese protocolo. Esto elimina el problema de no saber si el objeto responderá o no a 'contar', ya que ahora tiene un 'contrato' de tipo.

Si desea mantener la sintaxis de puntos con una propiedad, se puede declarar que en el protocolo:

@protocol FruitProtocol 

@property(readonly) NSDecimalNumber * count; 

- (NSDecimalNumber *)count 

@end 

y luego, su función sería:

-(NSDecimalNumber*)addCount:(id<FruitProtocol>)addObject{ 

    return [count decimalNumberByAdding:addObject.count]; 

} 
+0

¡También es genial! No entendí esto antes. ¡Gracias por el consejo! –

Cuestiones relacionadas