2015-03-18 6 views
2

Я получаю строку JSON, которую мне нужно перебирать, чтобы получить некоторые значения объектов. Это структураКак определить, является ли словарь пустым или нулевым

 
-meta 
-objects 
    |_cabdriver 
       |_employee 
    |client 

Есть объекты под деревом объектов, и есть также дочерние узлы, как извозчик и клиент. В кабриоле дочернего узла также есть еще один дочерний узел, называемый employee.

Это так, как я итерация его:

NSArray *messageArray = [json objectForKey:@"objects"]; 
historialServicios = [[NSMutableArray alloc]init]; 

// Parse and loop through the JSON 
for (dictionary in messageArray) { 
    //datos de nivel objects 
    NSString * date = [dictionary objectForKey:@"date"]; 
    NSString * origin = [dictionary objectForKey:@"origin"]; 
    NSString * destiny = [dictionary objectForKey:@"destiny"]; 
    NSString * rate = [dictionary objectForKey:@"service_rate"]; 
    NSString * state = [dictionary objectForKey:@"state"]; 
    NSString * time_service = [dictionary objectForKey:@"time_service"]; 
    NSString * id_service = [dictionary objectForKey:@"id"]; 

    //datos de nivel cliente 
    NSDictionary *level2Dict = [dictionary objectForKey:@"client"]; 
    NSString *client_id = [level2Dict objectForKey:@"id"]; 

    //datos de nivel cabdriver 
    NSDictionary *cabdriverLevelDict=[dictionary objectForKey:@"cabdriver"]; 

    //datos de nivel employee 
    NSDictionary *employeeLevelDict = [cabdriverLevelDict objectForKey:@"employee"]; 

    //datos del employee 
    NSString *driverName = [employeeLevelDict objectForKey:@"name"]; 
    NSString *driverLastname = [employeeLevelDict objectForKey:@"lastname"]; 
    NSString *driverPhone = [employeeLevelDict objectForKey:@"phone"]; 
    NSString *driverId = [employeeLevelDict objectForKey:@"id"]; 

    [historialServicios addObject:@{ 
            @"time_service": time_service, 
            @"id_service": id_service, 
            @"rate": rate, 
            @"destiny": destiny, 
            @"state": state, 
            @"origin": origin, 
            @"client_id":client_id, 
            @"date": date, 
            @"driverName":driverName, 
            @"driverLastname": driverLastname, 
            @"driverPhone": driverPhone, 
            @"driverId": driverId 

            }]; 
    NSLog(@"DESPUES DE ANADIR OBJETOS"); 
    NSLog(@"OBJETO ANADIDO==>TIME SERVICE = %@, ID SERVICE=%@, SERVICE RATE=%@,SERVICE DATE=%@,DESTINY=%@, STATE =%@,CLIENT ID=%@, ORIGIN=%@,DRIVER NAME=%@, DRIVER LASTNAME=%@,DRIVER PHONE=%@, DRIVER ID=%@",time_service,id_service,rate,date,destiny,state,client_id,origin,driverName,driverLastname,driverPhone,driverId); 

    //insertamos objetos en diccionario historialServicios 
} 

Все отлично работает, если объект имеет все узлы, но несколько раз, то извозчик узел пуст и не имеет сотрудник дочернего узла. Если это так, я получаю исключение, и приложение падает.

Как определить, существует ли сотрудник узла, и избежать исключения?

спасибо.

+0

Вы упомянули, что получаете исключение, но вы его не описали. На какой строке возникает исключение? Какова трассировка стека исключений? –

ответ

2

Вы можете объявить категорию для обработки значений [NSNull null], которые вводятся в ваш json.

@interface NSDictionary (NilNull) 
- (id)optionalObjectForKey:(id)key; 
- (id)optionalObjectForKey:(id)key defaultValue:(id)defaultValue; 
@end 

@implementation NSDictionary (NilNull) 
- (id)optionalObjectForKey:(id)key { 
    return [self optionalObjectForKey:key defaultValue:nil]; 
] 
- (id)optionalObjectForKey:(id)key defaultValue:(id)defaultValue { 
    id obj = [self objectForKey:key]; 
    return (obj == [NSNull null] || !obj) ? defaultValue : obj; 
} 
@end 

Затем используйте, что вместо того, чтобы:

NSDictionary *cabdriverLevelDict = [dictionary optionalObjectForKey:@"cabdriver"]; 
NSDictionary *employeeLevelDict = [cabdriverLevelDict optionalObjectForKey:@"employee"]; 

Вы еще не опубликовали содержимое вашего исключения, но судя по всему, это, вероятно, связано с попыткой добавить nil значения ваш новый словарь.

Затем используйте значение по умолчанию [NSNull null] для всех ваших поисков данных, которые создают объекты, с помощью которых вы создадите свой окончательный словарь. Полный исходный источник будет выглядеть следующим образом:

NSString * date = [dictionary optionalObjectForKey:@"date" defaultValue:[NSNull null]]; 
NSString * origin = [dictionary optionalObjectForKey:@"origin" defaultValue:[NSNull null]]; 
NSString * destiny = [dictionary optionalObjectForKey:@"destiny" defaultValue:[NSNull null]]; 
NSString * rate = [dictionary optionalObjectForKey:@"service_rate" defaultValue:[NSNull null]]; 
NSString * state = [dictionary optionalObjectForKey:@"state" defaultValue:[NSNull null]]; 
NSString * time_service = [dictionary optionalObjectForKey:@"time_service" defaultValue:[NSNull null]]; 
NSString * id_service = [dictionary optionalObjectForKey:@"id" defaultValue:[NSNull null]]; 

//datos de nivel cliente 
NSDictionary *level2Dict = [dictionary optionalObjectForKey:@"client" defaultValue:[NSDictionary dictionary]]; 
NSString *client_id = [level2Dict optionalObjectForKey:@"id" defaultValue:[NSNull null]]; 

//datos de nivel cabdriver 
NSDictionary *cabdriverLevelDict=[dictionary optionalObjectForKey:@"cabdriver" defaultValue:[NSDictionary dictionary]]; 

//datos de nivel employee 
NSDictionary *employeeLevelDict = [cabdriverLevelDict optionalObjectForKey:@"employee" defaultValue:[NSDictionary dictionary]]; 

//datos del employee 
NSString *driverName = [employeeLevelDict optionalObjectForKey:@"name" defaultValue:[NSNull null]]; 
NSString *driverLastname = [employeeLevelDict optionalObjectForKey:@"lastname" defaultValue:[NSNull null]]; 
NSString *driverPhone = [employeeLevelDict optionalObjectForKey:@"phone" defaultValue:[NSNull null]]; 
NSString *driverId = [employeeLevelDict optionalObjectForKey:@"id" defaultValue:[NSNull null]]; 
+0

Если вы создали такие методы, как dictOrNilForKey, которые возвращают NSDictionary * или nil, это было бы намного полезнее. Или stringOrNilForKey гарантирует возврат NSString * или nil. – gnasher729

+0

@ gnasher729: Это не было бы более полезно для требований OP. Требование о создании его словаря ('[historialServicios addObject: @ {...}]') состоит в том, что объекты, добавленные в словарь, не будут ** ** nil. Вот почему я специально создал методы, которые возвращают значение по умолчанию на '[NSNull null]' ** или ** 'nil'. –

+0

Спасибо, Ян, что вы имеете в виду с объявлением категории? Должен ли я создать новый класс из типа NSDictionary? – mvasco

0

проверка счетчик для словаря

if ([cabdriverLevelDict count] == 0) { 
NSLog("empty"); 
} 
else{ 
// Do your stuff !! 
} 
+0

Чем ты, но я бы предпочел форму ответа Яна. – mvasco

-2

Вы можете попробовать

NSDictionary *employeeLevelDict = [cabdriverLevelDict objectForKey:@"employee"]; 


if (employeeLevelDict.count != 0) 
{    
    // do something if dict is not empty 
} 
else 
{ 

}]; 
+0

Действительно ли нужно скопировать весь код для двух важных строк кода? –

+0

Чем ты, но я бы предпочел форму ответа Яна. – mvasco

1

Попробуйте здесь:

if(cabdriverLevelDict.allkeys.count){ 
    // Do something with the dict 
} else { 
    // dict is empty 
} 
+2

Вы просто скопировали все ключи в словаре без причины. Огромная потеря процессора и памяти. NSDictionary имеет собственный метод подсчета, поэтому используйте cabdriverLevelDict.count. – gnasher729

+1

Чем ты, но я бы предпочел форму ответа Яна. – mvasco

+0

@ gnasher729 ok, thx за советом, будьте в курсе! –

0
if (![cabdriverLevelDict isKindOfClass:[NSNull class]]){ 
    //do something 
} 

попробовать этот

+0

Что делать, если 'NSDictionary' уже инициализирован? Тогда условие было бы истинным, даже если нет объектов –

+0

Чем вы, но я бы предпочел форму ответа Ian. – mvasco

1

В принципе, вам нужно проверить каждый полученный результат. Если вы этого не сделаете, ваше приложение открыто для атак, и одна атака может позволить хакеру проникнуть в устройство пользователя и вызвать неограниченный ущерб. Где вы ожидаете словарь, вы можете получить нуль, вы можете получить нуль, вы можете получить число или строку, просто что-нибудь. Это довольно просто.

NSDictionary* dict = ...; 
if (! [dict isKindOfClass:[NSDictionary class]]) dict = nil; 

В Objective-C объекты nil вполне безопасны. Например, вы можете использовать objectForKey [@ "employee"], и все, что произойдет, это то, что в результате вы получите нуль. И все равно вы могли бы получить нуль.

Нет никакой точки проверки для [NSNull null], потому что любой другой результат, который дал вам сервер, приведет к краху вашего приложения.Просто проверьте, что вы на самом деле ожидаете. Отбросить неправильные данные - это хорошо, ведь десериализатор JSON выкинет все, если только один байт данных ошибочен.

Иногда вам нужно сделать немного больше заботы, потому что серверы плохо себя ведут, и вам приходится с этим справляться. Например, сервер должен возвращать массив словарей может дать вам только словарь, если есть только один, так что вы бы проверить, например

NSArray* arrayOfDicts = ...; 
if ([arrayOfDicts isKindOfClass:[NSDictionary class]] arrayOfDicts = @[arrayOfDicts]; 
else if (! [arrayOfDicts isKindOfClass:[NSArray class]] arrayOfDicts = nil; 
+0

Чем вы, но я бы предпочел ответную форму Яна. – mvasco

1

Как уже отмечалось, если какой-либо из объектов, передаваемых в словарь равен нулю, что вызовет исключение, которое приведет к сбою вашего приложения. Делая следующее:

[historialServicios addObject:@{ 
           @"time_service": time_service, 
           @"id_service": id_service, 
           @"rate": rate, 
           @"destiny": destiny, 
           @"state": state, 
           @"origin": origin, 
           @"client_id":client_id, 
           @"date": date, 
           @"driverName":driverName, 
           @"driverLastname": driverLastname, 
           @"driverPhone": driverPhone, 
           @"driverId": driverId 

           }]; 

Вы в зависимости, что все эти объекты (например, time_service, id_service и т.д.) не равны нулю. Как вы указали, они могут быть нулевыми, поэтому вам нужно иметь средства для проверки каждого объекта, который вы делаете. Я бы рекомендовал использовать в NSMutableDictionary, что делает метод категории, что только добавляет пару ключ/значение, если они оба не ноль:

@implementation NSMutableDictionary (Util) 

-(void)setObjectOrRemoveIfNil:(id)anObject forKey:(id<NSCopying>)aKey 
{ 
    if (anObject == nil) 
    { 
     [self removeObjectForKey:aKey]; 
    } 
    else 
    { 
     [self setObject:anObject forKey:aKey]; 
    } 
} 

@end 

А затем соединить ваш словарь так:

NSMutableDictionary* values = [NSMutableDictionary dictionary]; 
[values setObjectOrRemoveIfNil:time_service forKey:@"time_service"]; 
[values setObjectOrRemoveIfNil:id_service forKey:@"id_service"]; 
//Keep going with the rest of your values. 

Наконец мы используем этот словарь, как вы уже писали:

[historialServicios addObject:values]; 
+0

Чем ты, но я бы предпочел форму ответа Яна. – mvasco

Смежные вопросы