Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c NSManagedObject属性值的NSNull处理_Objective C_Json_Parsing_Nsmanagedobject_Nsnull - Fatal编程技术网

Objective c NSManagedObject属性值的NSNull处理

Objective c NSManagedObject属性值的NSNull处理,objective-c,json,parsing,nsmanagedobject,nsnull,Objective C,Json,Parsing,Nsmanagedobject,Nsnull,我正在为我的NSManagedObject的属性设置值,这些值来自从JSON文件正确序列化的NSDictionary。我的问题是,当某个值为[NSNull null]时,我无法直接分配给属性: fight.winnerID = [dict objectForKey:@"winner"]; 这会引发一个NSInvalidArgumentException "winnerID"; desired type = NSString; given type = NSNull; value = &

我正在为我的
NSManagedObject
的属性设置值,这些值来自从JSON文件正确序列化的
NSDictionary
。我的问题是,当某个值为
[NSNull null]
时,我无法直接分配给属性:

    fight.winnerID = [dict objectForKey:@"winner"];
这会引发一个
NSInvalidArgumentException

"winnerID"; desired type = NSString; given type = NSNull; value = <null>;
但我认为这并不优雅,而且会因为要设置很多属性而变得混乱

此外,在处理
NSNumber
属性时,这会变得更加困难:

fight.round = [NSNumber numberWithUnsignedInteger:[[dict valueForKey:@"round"] unsignedIntegerValue]]
NSInvalidArgumentException
现在是:

[NSNull unsignedIntegerValue]: unrecognized selector sent to instance
在这种情况下,我必须先处理
[dict valueForKey:@“round”]
,然后再对其生成
nsuiger
值。而单线解决方案已经不复存在

我尝试创建一个@try@catch块,但是一旦捕获到第一个值,它就会跳过整个@try块,并且忽略下一个属性


是否有更好的方法来处理
[NSNull null]
,或者使其完全不同但更简单?

如果将其包装在宏中,可能会更简单一些:

#define NULL_TO_NIL(obj) ({ __typeof__ (obj) __obj = (obj); __obj == [NSNull null] ? nil : obj; })
然后你可以写这样的东西

fight.winnerID = NULL_TO_NIL([dict objectForKey:@"winner"]);

或者,您可以预先处理您的字典,在尝试将其填充到托管对象之前,将所有的
NSNull
替换为
nil

我编写了两个分类方法,在使用之前从JSON生成的字典或数组中去除null:

@implementation NSMutableArray (StripNulls)

- (void)stripNullValues
{
    for (int i = [self count] - 1; i >= 0; i--)
    {
        id value = [self objectAtIndex:i];
        if (value == [NSNull null])
        {
            [self removeObjectAtIndex:i];
        }
        else if ([value isKindOfClass:[NSArray class]] ||
                 [value isKindOfClass:[NSDictionary class]])
        {
            if (![value respondsToSelector:@selector(setObject:forKey:)] &&
                ![value respondsToSelector:@selector(addObject:)])
            {
                value = [value mutableCopy];
                [self replaceObjectAtIndex:i withObject:value];
            }
            [value stripNullValues];
        }
    }
}

@end


@implementation NSMutableDictionary (StripNulls)

- (void)stripNullValues
{
    for (NSString *key in [self allKeys])
    {
        id value = [self objectForKey:key];
        if (value == [NSNull null])
        {
            [self removeObjectForKey:key];
        }
        else if ([value isKindOfClass:[NSArray class]] ||
                 [value isKindOfClass:[NSDictionary class]])
        {
            if (![value respondsToSelector:@selector(setObject:forKey:)] &&
                ![value respondsToSelector:@selector(addObject:)])
            {
                value = [value mutableCopy];
                [self setObject:value forKey:key];
            }
            [value stripNullValues];
        }
    }
}

@end

如果标准的JSON解析库在默认情况下具有这种行为,那就太好了——省略空对象几乎总是比将它们作为NSNull包含更好。

好的,我今天早上刚刚醒来,发现了一个好的解决方案。那么这个呢:

使用接收可变数组和字典的选项序列化JSON:

NSMutableDictionary *rootDict = [NSJSONSerialization JSONObjectWithData:_receivedData options:NSJSONReadingMutableContainers error:&error];
...
从leafDict获取一组具有
[NSNull null]
值的键:

NSSet *nullSet = [leafDict keysOfEntriesWithOptions:NSEnumerationConcurrent passingTest:^BOOL(id key, id obj, BOOL *stop) {
    return [obj isEqual:[NSNull null]] ? YES : NO;
}];
[leafDict removeObjectsForKeys:[nullSet allObjects]];
从可变leafDict中删除筛选的属性:

NSSet *nullSet = [leafDict keysOfEntriesWithOptions:NSEnumerationConcurrent passingTest:^BOOL(id key, id obj, BOOL *stop) {
    return [obj isEqual:[NSNull null]] ? YES : NO;
}];
[leafDict removeObjectsForKeys:[nullSet allObjects]];
现在,当您调用
fight.winnerID=[dict objectForKey:@“winner”]
winnerID将自动变为
(null)
nil
,而不是
[NSNull null]

与此无关,但我也注意到,在将字符串解析为NSNumber时,最好使用
NSNumberFormatter
,我所做的方法是从一个nil字符串中获取
integerValue
,这给了我一个不需要的NSNumber
0
,而实际上我希望它为nil

之前:

// when [leafDict valueForKey:@"round"] == nil
fight.round = [NSNumber numberWithInteger:[[leafDict valueForKey:@"round"] integerValue]]
// Result: fight.round = 0
之后:

__autoreleasing NSNumberFormatter* numberFormatter = [[NSNumberFormatter alloc] init];
fight.round = [numberFormatter numberFromString:[leafDict valueForKey:@"round"]];    
// Result: fight.round = nil
另一种方法是

-[NSObject setValuesForKeysWithDictionary:]
在这种情况下,您可以这样做

[fight setValuesForKeysWithDictionary:dict];
在标题NSKeyValueCoding.h中,它定义了“值为NSNull的字典条目将导致
-setValue:nil-forKey:key
消息发送到接收方

唯一的缺点是您必须将字典中的任何键转换为接收器中的键

dict[@"winnerID"] = dict[@"winner"];
[dict removeObjectForKey:@"winner"];

我也遇到了同样的问题,找到了这篇文章,用了一种稍有不同的方式。只使用分类-

为“NSDictionary”创建一个新的类别文件,并添加此方法-

@implementation NSDictionary (SuperExtras)

- (id)objectForKey_NoNSNULL:(id)aKey
{
    id result = [self objectForKey:aKey];

if(result==[NSNull null])
{
    return nil;
}

return result;

}

@end
稍后要在代码中使用它,对于可以包含NSNULL的属性,只需这样使用-

newUser.email = [loopdict objectForKey_NoNSNULL:@"email"];

这就是问题所在

出于好奇,在数字的情况下,为什么要展开并重新包装数字?fight.round=[dict objectForKey:@“round”]?@KevinBallard属性的值类型不可接受:property=“round”"; 所需类型=编号;给定类型=uu NSCFString;value=3。如果它是
NSString
,则
-unsignedIntegerValue
将不起作用,因为该方法未在
NSString
上定义。您可以使用
-integerValue
,它在
NSNumber
NSString
上都有定义。谢谢,这很有用!你推荐一个好的来源来了解宏吗?@Lucien:我希望我推荐,但是没有。虽然有很多信息,所以只需谷歌一下。@Kevin Ballard。。。。真是太棒了。。。。。非常有用。。。。。你是天才。。。快乐编码!!!!!!我如何在swift中实现这一点?找到这个答案func nullToNil(值:Any?->Any?{if value为NSNull{return nil}else{return value}}people.age=nullToNil(peopleDict[“age”])