Заменить все объекты NSNull в NSDictionary
Мне любопытно, у меня в настоящее время есть NSDictionary
, где некоторые значения устанавливаются в объект NSNull
благодаря помощи json-framework.
Цель состоит в том, чтобы удалить все значения NSNull
и заменить его пустой строкой.
Я уверен, что кто-то это сделал? Несомненно, это, вероятно, четыре лайнера, и это просто, я просто слишком сгорел, чтобы понять это самостоятельно.
Спасибо!
Ответы
Ответ 1
Действительно просто:
@interface NSDictionary (JRAdditions)
- (NSDictionary *)dictionaryByReplacingNullsWithStrings;
@end
@implementation NSDictionary (JRAdditions)
- (NSDictionary *)dictionaryByReplacingNullsWithStrings {
const NSMutableDictionary *replaced = [self mutableCopy];
const id nul = [NSNull null];
const NSString *blank = @"";
for(NSString *key in self) {
const id object = [self objectForKey:key];
if(object == nul) {
//pointer comparison is way faster than -isKindOfClass:
//since [NSNull null] is a singleton, they'll all point to the same
//location in memory.
[replaced setObject:blank
forKey:key];
}
}
return [replaced copy];
}
@end
Использование:
NSDictionary *someDictThatHasNulls = ...;
NSDictionary *replacedDict = [someDictThatHasNulls dictionaryByReplacingNullsWithStrings];
Ответ 2
Я внес несколько изменений в исходный ответ Джейкоба, чтобы расширить его, чтобы обрабатывать словари и массивы, хранящиеся в оригинальном словаре.
#import "NSDictionary+NullReplacement.h"
#import "NSArray+NullReplacement.h"
@implementation NSDictionary (NullReplacement)
- (NSDictionary *)dictionaryByReplacingNullsWithBlanks {
const NSMutableDictionary *replaced = [self mutableCopy];
const id nul = [NSNull null];
const NSString *blank = @"";
for (NSString *key in self) {
id object = [self objectForKey:key];
if (object == nul) [replaced setObject:blank forKey:key];
else if ([object isKindOfClass:[NSDictionary class]]) [replaced setObject:[object dictionaryByReplacingNullsWithBlanks] forKey:key];
else if ([object isKindOfClass:[NSArray class]]) [replaced setObject:[object arrayByReplacingNullsWithBlanks] forKey:key];
}
return [NSDictionary dictionaryWithDictionary:[replaced copy]];
}
@end
А также категория массива, конечно:
#import "NSArray+NullReplacement.h"
#import "NSDictionary+NullReplacement.h"
@implementation NSArray (NullReplacement)
- (NSArray *)arrayByReplacingNullsWithBlanks {
NSMutableArray *replaced = [self mutableCopy];
const id nul = [NSNull null];
const NSString *blank = @"";
for (int idx = 0; idx < [replaced count]; idx++) {
id object = [replaced objectAtIndex:idx];
if (object == nul) [replaced replaceObjectAtIndex:idx withObject:blank];
else if ([object isKindOfClass:[NSDictionary class]]) [replaced replaceObjectAtIndex:idx withObject:[object dictionaryByReplacingNullsWithBlanks]];
else if ([object isKindOfClass:[NSArray class]]) [replaced replaceObjectAtIndex:idx withObject:[object arrayByReplacingNullsWithBlanks]];
}
return [replaced copy];
}
@end
С помощью этого вы можете взять любой массив или словарь и рекурсивно уничтожить все экземпляры [NSNull null].
Надеюсь, что это поможет кому-то.
-Brandon
P.S. Для полной загрузки, вот файлы заголовков:
@interface NSDictionary (NullReplacement)
- (NSDictionary *)dictionaryByReplacingNullsWithBlanks;
@end
И заголовок массива:
@interface NSArray (NullReplacement)
- (NSArray *)arrayByReplacingNullsWithBlanks;
@end
Ответ 3
Перемещение по поиску словаря для NSNull - один из способов решения этой проблемы, но я сделал несколько более ленивый подход. Вместо nil вы можете назначить пустую строку, но принцип тот же.
CPJSONDictionary.h
@interface NSDictionary (CPJSONDictionary)
- (id)jsonObjectForKey:(id)aKey;
@end
CPJSONDictionary.m
@implementation NSDictionary (CPJSONDictionary)
- (id)jsonObjectForKey:(id)aKey {
id object = [self objectForKey:aKey];
if ([object isKindOfClass:[NSNull class]]) {
object = nil;
}
return object;
}
@end
Ответ 4
другая вариация:
NSDictionary * NewDictionaryReplacingNSNullWithEmptyNSString(NSDictionary * dict) {
NSMutableDictionary * const m = [dict mutableCopy];
NSString * const empty = @"";
id const nul = [NSNull null];
NSArray * const keys = [m allKeys];
for (NSUInteger idx = 0, count = [keys count]; idx < count; ++idx) {
id const key = [keys objectAtIndex:idx];
id const obj = [m objectForKey:key];
if (nul == obj) {
[m setObject:empty forKey:key];
}
}
NSDictionary * result = [m copy];
[m release];
return result;
}
Результат такой же, как и, похоже, почти идентичен Jacob's, но требования к скорости и памяти составляют от половины до одной трети (ARC или MRC) в тестах, которые я сделал. Конечно, вы также можете использовать его как метод категории.
Ответ 5
Я протестировал решение Stakenborg. Он работает хорошо, но у него есть следующая проблема. Если ожидается, что какой-то объект будет номером, преобразование его в NSNull
может быть источником ошибки.
Я создал новый метод для прямого удаления записей NSNull
. Таким образом, вам нужно только проверить, существует ли соответствующий ключ.
Добавить в NSDictionary+NullReplacement
- (NSDictionary *)dictionaryByRemovingNulls{
const NSMutableDictionary *replaced = [self mutableCopy];
const id nul = [NSNull null];
for (NSString *key in self) {
id object = [self objectForKey:key];
if (object == nul) [replaced removeObjectForKey:key];
else if ([object isKindOfClass:[NSDictionary class]]) [replaced setObject:[object dictionaryByRemovingNulls] forKey:key];
else if ([object isKindOfClass:[NSArray class]]) [replaced setObject:[object arrayByRemovingNulls] forKey:key];
}
return [NSDictionary dictionaryWithDictionary:[replaced copy]];
}
И в NSArray+NullReplacement
- (NSArray *)arrayByRemovingNulls {
NSMutableArray *replaced = [self mutableCopy];
const id nul = [NSNull null];
for (int idx = [replaced count]-1; idx >=0; idx--) {
id object = [replaced objectAtIndex:idx];
if (object == nul) [replaced removeObjectAtIndex:idx];
else if ([object isKindOfClass:[NSDictionary class]]) [replaced replaceObjectAtIndex:idx withObject:[object dictionaryByRemovingNulls]];
else if ([object isKindOfClass:[NSArray class]]) [replaced replaceObjectAtIndex:idx withObject:[object arrayByRemovingNulls]];
}
return [replaced copy];
}
Я надеюсь, что это поможет
Ответ 6
Вот мое решение:
+ (NSDictionary *)cleanNullInJsonDic:(NSDictionary *)dic
{
if (!dic || (id)dic == [NSNull null])
{
return dic;
}
NSMutableDictionary *mulDic = [[NSMutableDictionary alloc] init];
for (NSString *key in [dic allKeys])
{
NSObject *obj = dic[key];
if (!obj || obj == [NSNull null])
{
// [mulDic setObject:[@"" JSONValue] forKey:key];
}else if ([obj isKindOfClass:[NSDictionary class]])
{
[mulDic setObject:[self cleanNullInJsonDic:(NSDictionary *)obj] forKey:key];
}else if ([obj isKindOfClass:[NSArray class]])
{
NSArray *array = [BasicObject cleanNullInJsonArray:(NSArray *)obj];
[mulDic setObject:array forKey:key];
}else
{
[mulDic setObject:obj forKey:key];
}
}
return mulDic;
}
+ (NSArray *)cleanNullInJsonArray:(NSArray *)array
{
if (!array || (id)array == [NSNull null])
{
return array;
}
NSMutableArray *mulArray = [[NSMutableArray alloc] init];
for (NSObject *obj in array)
{
if (!obj || obj == [NSNull null])
{
// [mulArray addObject:[@"" JSONValue]];
}else if ([obj isKindOfClass:[NSDictionary class]])
{
NSDictionary *dic = [self cleanNullInJsonDic:(NSDictionary *)obj];
[mulArray addObject:dic];
}else if ([obj isKindOfClass:[NSArray class]])
{
NSArray *a = [BasicObject cleanNullInJsonArray:(NSArray *)obj];
[mulArray addObject:a];
}else
{
[mulArray addObject:obj];
}
}
return mulArray;
}
Ответ 7
-(NSDictionary*)stripNulls:(NSDictionary*)dict{
NSMutableDictionary *returnDict = [NSMutableDictionary new];
NSArray *allKeys = [dict allKeys];
NSArray *allValues = [dict allValues];
for (int i=0; i<[allValues count]; i++) {
if([allValues objectAtIndex:i] == (NSString*)[NSNull null]){
[returnDict setValue:@"" forKey:[allKeys objectAtIndex:i]];
}
else
[returnDict setValue:[allValues objectAtIndex:i] forKey:[allKeys objectAtIndex:i]];
}
return returnDict;
}
Ответ 8
Категория на nsnull, которая возвращает nil, кажется, также имеет смысл, по крайней мере для меня. Есть несколько. Один заставляет все вызовы возвращать нуль, что, кажется, имеет смысл. Извините, нет ссылки. Я думаю, если вам нужно будет использовать nspropertylistserialization, то категория может не работать для вас.