2011-05-24 15 views
7

Quiero almacenar un conjunto de pares clave de valores, siendo la clave mi propio objeto (ObjectA) que hereda de NSObject y el valor es un int.
Estoy tratando de usar un NSMutableDictionary. Me entender que se puede sólo los tipos de tienda de objetos en el diccionario, así que tengo la siguiente:Claves de objeto con NSMutableDictionary (Objective-C)

id value = [NSNumber numberWithInt:my_number]; 

[[self dictionary] setObject:value forKey:myObjectA]; 

Ahora que me da un error diciendo

- [Objecta copyWithZone:]: Selector no reconocido envió a la instancia

que está bien, entiendo que las claves de objeto deben implementar el protocolo NSCopying. Sin embargo, luego leo que puedes hacer esto al envolver tus objetos usando NSValue.

¿Puede alguien explicar cómo envolvería mis objetos y cómo puedo encontrar el valor con la llave? ¿Todavía puedo usar dictionary objectForKey:myObjectA o tengo que envolver myObjectA con un objeto NSValue mientras estoy buscando? ¿O debería implementar NSCopying en mi clase personalizada o usar una clave de cadena en su lugar?

Estoy buscando la forma más simple y sencilla de usar un diccionario, si tengo que implementar una clave de cadena y usar setValue: forKey: en su lugar, pero prefiero usar la clave del objeto si puedo.

Respuesta

10

Las claves del diccionario siempre se copian. Por lo tanto, solo necesita implementar el protocolo NSCopying para su clase, que es solo el método copyWithZone:.

Además, debe implementar el método isEqual: para su clase.

Editar: Cómo implementar su copyWithZone: depende de una serie de factores (factor principal: copia profunda vs. poco profunda). Consulte la guía Implementing Object Copy de Apple y this SO answer.

+0

¿Podría ampliar su respuesta para incluir lo que pondría en mi implementación copyWithZone en mi propia clase? – link664

+0

@ link664: Actualicé mi respuesta. – DarkDust

+2

Necesita implementar '-hash' si implementa' -isEqual: 'Si dos objetos son iguales como lo determina' -isEqual: ', entonces deben tener el mismo valor hash. – JeremyP

6

Usted puede convertir una id en un NSValue con:

NSValue* value = [NSValue valueWithNonretainedObject:object]; 
... 
id object_ = [value nonretainedObjectValue]; 

pero es necesario para gestionar la propiedad fuera del diccionario. Esto va a ser un desastre. Es mejor adoptar NSCopying.


También hay una cuarta opción: utilizar un CFDictionary, lo que permite que el objeto sólo puede ser CFRetain/CFReleased, no copiado.

CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
    kCFAllocatorDefault, 0, 
    &kCFTypeDictionaryKeyCallBacks, 
    &kCFTypeDictionaryValueCallBacks 
); 

... 

CFDictionarySetValue(dict, myObjectA, value); 
... 

CFRelease(dict); 

Y si estás programando para Mac o iOS 6 o superior, tratar NSMapTable.

NSMapTable* dict = [[NSMapTable mapTableWithStrongToStrongObjects] retain]; 
... 
[dict setObject:@"?" forKey:foo]; 
... 
[dict release]; 
+0

Gracias por la sugerencia sobre el uso de NSValue. No estaba al tanto de esa utilidad y era justo lo que necesitaba. Parece una solución más apropiada para el problema. –

0

No necesita envolver su objeto usando NSValue. Lo que tienes funcionará, excepto que te falta una pieza. Para la clase de myObjectA, debe adoptar el protocolo NSCopying (consulte the docs para saber qué agregar). Una vez que se haya agregado, el código que publicó anteriormente debería funcionar correctamente.

Es posible que desee considerar el uso de cadenas en su propio objeto para la clave. Se requiere que la clave sea una cadena si la clave-valor de codificación va a ser utilizada para acceder a ella en absoluto. Por lo tanto, usar una cadena facilitará la vida si puede aprovechar la codificación de clave-valor en cualquier lugar en el que use el diccionario.

Cuestiones relacionadas