¿Cómo gestiona NSDictionary los objects NIL?

Considere el siguiente código. En esencia, obtenemos 2 cadenas, luego agregamos estos valores al NSDictionary.

Sin embargo, llegué a un error extraño. Cuando fbAccessTokenKey es 0x0 (o nil), entonces twitterToken no se agregaría también.

NSString *fbAccessTokenKey=[[UserStockInfo shanetworkingUserStockInfo] getFBAccessTokenKey]; NSString *twitterToken=[[UserStockInfo shanetworkingUserStockInfo] getTwitterAccessTokenKey]; NSDictionary *params= [[NSDictionary alloc] initWithObjectsAndKeys: fbAccessTokenKey, @"fb_access_token", twitterToken, @"twitter_access_token", nil ]; 

¿Por qué sucede esto y cuál es una buena forma de resolverlo?

nil se utiliza como 'centinela' para marcar la list de "fin de arguments". Si twitterToken fuera nulo, el time de ejecución iría a través de sus arguments, y una vez que llegara a twitterToken , pensaría que era hasta el final de su list de objects y keys. Esto se debe a la forma en que C / Obj-C se implementa cuando se trata de enumerar arguments.

La forma alternativa y segura de hacerlo es usar un NSMutableDictionary , y comprobar si sus valores son no nulos, luego agregarlos al dictionary mutable así:

 NSString *fbAccessTokenKey = [[UserStockInfo shanetworkingUserStockInfo] getFBAccessTokenKey]; NSString *twitterToken = [[UserStockInfo shanetworkingUserStockInfo] getTwitterAccessTokenKey]; NSMutableDictionary *params = [NSMutableDictionary dictionary]; if (fbAccessTokenKey) [params setObject:fbAccessTokenKey forKey:@"fb_access_token"]; if (twitterToken) [params setObject:twitterToken forKey:@"twitter_access_token"]; 

Para get más información técnica, hay un buen artículo sobre Cocoa with Love: http://cocoawithlove.com/2009/05/variable-argument-lists-in-cocoa.html

En lugar de inicializar con initWithObjectAndKeys. ¿Por qué no instanciar un NSMutableDictionary y luego agregar los pares de valores key (o no si la key es nula)?

 NSMutableDictionary * params = [[NSMutableDictionary alloc] init]; if (fbAccessTokenKey) [params setObject:fbAccessTokenKey forKey:@"fb_access_token]; // ... etc 

Podría devolverlo a un NSDictionary más adelante si desea mantenerlo inmutable a partir de ese momento.

Actualizar

Solo una nota en respuesta al comentario de Josh , debo aclarar que, por supuesto, el elenco no convertirá mágicamente los params NSMutableDictionary en un NSDictionary. Pero si lo pasas al código que requiere un NSDictionary, el elenco te permitirá tratarlo como tal.

El comentario de Josh incluye este código:

 NSMutableDictionary * md = [[NSMutableDictionary alloc] init]; NSDictionary * d = (NSDictionary *)md; [d setObject:@"Yes I am" forKey:@"Still mutable?"]; NSLog(@"%@", d); // Prints { "Still mutable?" = Yes I am; } 

Esto generará la siguiente advertencia del comstackdor (y para mí, con advertencias generando errores, un error de compilation):

file: blah.m: error: Problema semántico: 'NSDictionary' puede no responder a 'setObject: forKey:'