¿Cómo acceder de manera eficiente a objetos grandes en Obj-C usando objectForKey y objectAtIndex?

Si tengo un NSDirectory grande típicamente de un objeto JSON analizado, puedo acceder a este objeto con un código como este:

[[[[[obj objectForKey:@"root"] objectForKey:@"key1"] objectAtIndex:idx] objectForKey:@"key2"] objectAtIndex:idz];

La línea podría ser mucho más larga que esto.

¿Puedo optimizar este código de alguna manera? ¿Al menos hacer que sea más fácil de leer?

Esta línea también generará un error de tiempo de ejecución si el objeto no corresponde, ¿cuál es la forma más eficiente de evitarlo?

preguntado el 04 de julio de 12 a las 09:07

Si está utilizando la versión correcta de Xcode, puede hacer esto: obj[@"root"][@"key1"][idx][@"key2"][idz] - un poco más legible (y compatible con versiones anteriores) pero no es realmente el camino a seguir... -

¡Eso es muy bueno! Parece que no funciona en 4.3.2!? -

Xcode 4.4 es tu amigo. Developer Preview ya está disponible, la versión final estará disponible este mes. -

4 Respuestas

Si estuvieras usando -objectForKey: por todo lo que puedas usar -valueForKeyPath:, como en

[obj valueForKeyPath:@"key1.key2.key3.key4"]

Sin embargo, esto no funciona cuando necesita usar -objectAtIndex:. No creo que haya ninguna buena solución para ti. -valueForKeyPath: tampoco resolvería el problema de los errores de tiempo de ejecución.

Si realmente desea una forma sencilla de hacer esto, puede escribir su propia versión de -valueForKeyPath: (llámelo de otra manera) que proporciona una sintaxis para especificar un -objectAtIndex: en lugar de una clave, y que realiza las comprobaciones dinámicas adecuadas para garantizar que el objeto realmente responda al método en cuestión.

Respondido 04 Jul 12, 09:07

haré mi propio valueForKeyPath. Gracias :) - Gustav

Si desea un código más fácil de leer, puede dividir la línea en varias líneas como esta

 MyClass *rootObject = [obj objectForKey:@"root"];
 MyClass *key1Object = [rootObject objectForKey:@"key1"];
 MyClass *myObject = [key1Object objectAtIndex:idx];
 ...

Etcétera.

Respondido 04 Jul 12, 09:07

Creo que puede crear una matriz que contendrá la "ruta" completa a su objeto. Lo único, necesita almacenar sus índices de alguna manera, tal vez en NSNumber, en este caso no puede usar objetos NSNumber como claves en sus diccionarios. Luego cree un método que devolverá el objeto necesario para esta "ruta" dada. algo como

NSMutableArray* basePath = [NSMutableArray arrayWithObjects: @"first", [NSNumber numberWithInt:index], nil];
id object = [self objectForPath:basePath inContainer:container];

- (id) objectForPath:(NSMutableArray*)basePath inContainer:(id)container
{
    id result = nil;
    id pathComponent = [basePath objectAtIndex: 0];
    [basePath removeObjectAtIndex: 0];

    // check if it is a number with int index
    if( [pathComponent isKindOfClass:[NSNumber class]] ) 
    {
        result = [container objectAtIndex: [pathComponent intValue]];
    }
    else
    {
        result = [container objectForKey: pathComponent];
    }

    assert( result != nil );

    // check if it is need to continue searching object
    if( [basePath count] > 0 )
    {
        return [self objectForPath:basePath inContainer: result];
    }
    else
    {
        return result;
    }
}

esto es solo una idea, pero espero que entiendas lo que quiero decir. Y como Kevin mencionó anteriormente, si no tiene índices, puede usar la codificación de clave-valor.

Respondido 04 Jul 12, 09:07

No sé si te puede ir bien, pero también podrías probar con los bloques, siempre me parecen muy convenientes. Al menos hicieron el código mucho más legible.

NSArray *filter = [NSArray arrayWithObjects:@"pathToFind", @"pathToFind2",nil];

NSPredicate *filterBlock = [NSPredicate predicateWithBlock: ^BOOL(id obj, NSDictionary *bind){        
    NSArray *root = (NSArray*)obj;

    // cycle the array and found what you need.
    // eventually implementing some sort of exit strategy

}];

[rootObject filteredArrayUsingPredicate:filterBlock];

Respondido 04 Jul 12, 09:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.