2011-03-18 13 views
5

necesito para determinar si un objeto está incluido en una relación a muchos de Datos Básicos (que es un NSSet), y yo estoy tratando de decidir cuál de las dos soluciones es mejor:¿Qué es mejor, NSSet containsObject o fast enum?

Solución 1)

if ([managedObject.items containsObject:itemOfInterest]) 
    return … 

Solución 2)

for (NSManagedObject *item in managedObject.items) 
    if ([item == itemOfInterest]) 
     return … 

Solución 1 es más conciso, pero el NSSet Clase Ref dice rápida enumeración se comporta mejor que objectEnumerator de NSSet. ¿También funciona mejor que containsObject?

+0

Me puede estar perdiendo algo aquí, pero ¿por qué necesita buscar en absoluto? Si ya tiene ambos objetos en cada lado de una relación, ya tiene la información que necesita. ¿Es esta una relación de muchos a muchos o uno a muchos sin reciprocidad? – TechZen

+0

@TechZen: se realiza una búsqueda por criterio de búsqueda del usuario. Los resultados se muestran en una tabla.El usuario realiza una subselección de estos resultados a través de la tabla. Hay otra tabla con miembros de la relación de muchos, presentada con casillas de verificación. Los estados de la casilla de verificación se deben establecer según si todos, ninguno o algunos de los objetos seleccionados contienen su elemento. Puede haber muchos objetos involucrados, por lo que es importante usar el método más eficiente. Gracias al consejo de los Sres. Raybould y Napier, estoy seguro de que containsObject es el camino a seguir. – Wienke

Respuesta

5

que siempre iría a por la opción 1.

Su más concisa, lo que puedo decir exactamente lo que su tratando de hacer con el código y lo más probable es que el containsObject contiene algunas optimizaciones muy elegante.

20

Ninguno. Debe usar un NSFetchRequest con un predicado. Sus patrones pueden fallar accidentalmente en toda la relación, lo cual es muy costoso y no es necesario solo para verificar si contiene un objeto. Hay maneras de ser cuidadoso y no culpar a toda la relación, pero es frágil (pequeños cambios en su búsqueda conducen a grandes cambios en el rendimiento) y, por lo tanto, es mejor tener el hábito de usar NSFetchRequest en lugar de la colección para buscar. Me gusta establecer mi fetchLimit en 1 en estos casos, así que una vez que lo encuentra, deja de buscar.

Para su conveniencia, es posible que desee crear un método -containsFoo: en su objeto administrado para que no tenga que escribir la lógica de búsqueda por todos lados.

Sus dos soluciones anteriores son sutilmente diferentes. El primero prueba si hay un objeto en la colección que isEqual: a itemOfInterest. Su segunda solución prueba si hay un objeto en la colección en la misma ubicación de memoria que itemOfInterest. Para objetos con lógica personalizada isEqual:, estos pueden arrojar resultados diferentes. Esto significa que la solución 2 podría ser un poco más rápida para colecciones de datos no centrales, pero es porque en realidad está probando algo diferente, no debido a la enumeración de objetos. (En realidad, esto solo es válido para colecciones pequeñas; consulte a continuación.)

¿Por qué cree que la solución 1 usa -objectEnumerator?

Como lo señala @James Raybould, generalmente no debe intentar reescribir los métodos integrados por motivos de rendimiento. Si una versión isEqual: de la Solución 2 fuera más rápida que la Solución 1, ¿no crees que Apple hubiera implementado -containsObject: usando el código en la solución 2?

En realidad, el CFSet subyacente se implementa como un hash, por lo que la comprobación de la contención es logarítmica en lugar de lineal. En términos generales, para conjuntos grandes con funciones hash razonables, la solución 1 será más rápida. Vea el código para él en CFSet.c. Busque CFSetContainsValue(). No está garantizado que la implementación de CFSet siga siendo la misma, por supuesto, pero es útil para entender cómo las preocupaciones sobre el rendimiento generalmente se abordan en Cocoa.

+1

Ignora mi comentario: ¡esta es una de las mejores respuestas que jamás haya leído! –

+0

Gracias por su respuesta en profundidad. Aprendí mucho de eso. La búsqueda en cuestión se realiza en una selección de objetos gestionados en una tabla, cuyo contenido es en sí mismo el resultado de una solicitud de recuperación en particular. Así que realmente necesito trabajar con objetos en caché, en lugar de ejecutar otra búsqueda. (Utilizo un fetch con un "predicateWithFormat: @" ANY items ==% @ ", itemSelected" cuando extraigo objetos de la tienda en función de esta relación múltiple). – Wienke

+0

Su situación suena razonable, y 'containsObject:' es su mejor apuesta aquí, como señala James. Tiene razón en que no debe volver a buscar *. Y 'containsObject:' usa 'hash' y' isEqual: 'que están documentados para no tener errores (nunca debe anular estos métodos) para un 'NSManagedObject'). –