source

NSManagedObject 속성 값에 대한 NSNull 처리

goodcode 2023. 3. 27. 23:12
반응형

NSManagedObject 속성 값에 대한 NSNull 처리

내 속성에 대한 값을 설정하고 있습니다.NSManagedObject, 이러한 값들은,NSDictionaryJSON 파일에서 올바르게 직렬화되었습니다.제 문제는, 어떤 가치가[NSNull null], 속성에 직접 할당할 수 없습니다.

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

이 때문에NSInvalidArgumentException

"winnerID"; desired type = NSString; given type = NSNull; value = <null>;

나는 쉽게 값을 확인할 수 있었다.[NSNull null]할당하다nil대신:

fight.winnerID = [dict objectForKey:@"winner"] == [NSNull null] ? nil : [dict objectForKey:@"winner"];

하지만 이건 우아하지 않고 설정해야 할 속성들이 많아서 지저분하다고 생각해요.

그리고 이게 더 어려워지고NSNumber속성:

fight.round = [NSNumber numberWithUnsignedInteger:[[dict valueForKey:@"round"] unsignedIntegerValue]]

NSInvalidArgumentException현재:

[NSNull unsignedIntegerValue]: unrecognized selector sent to instance

이 경우 치료해야 합니다[dict valueForKey:@"round"]만들기 전에NSUInteger가치가 있습니다.단 한 줄의 솔루션도 사라졌습니다.

@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관리 대상 오브젝트에 넣으려고 시도하기도 전에 말이죠.

좋아요, 오늘 아침에 일어나서 좋은 해결책을 찾았어요.이건 어때?

Mutable Arrays and Dictionary 수신 옵션을 사용하여 JSON을 시리얼화합니다.

NSMutableDictionary *rootDict = [NSJSONSerialization JSONObjectWithData:_receivedData options:NSJSONReadingMutableContainers error:&error];
...

다음을 포함하는 키 세트를 가져옵니다.[NSNull null]값을 지정합니다.

NSSet *nullSet = [leafDict keysOfEntriesWithOptions:NSEnumerationConcurrent passingTest:^BOOL(id key, id obj, BOOL *stop) {
    return [obj isEqual:[NSNull null]] ? YES : NO;
}];

Mutable leafDict에서 필터링된 속성을 제거합니다.

[leafDict removeObjectsForKeys:[nullSet allObjects]];

지금 당신이 전화했을 때fight.winnerID = [dict objectForKey:@"winner"];winnerID는 자동적으로(null)또는nil와는 반대로<null>또는[NSNull null].

이것과는 관계없지만, 저는 또한 이 제품을 사용하는 것이 더 낫다는 것을 깨달았습니다.NSNumberFormatterNS Number에 문자열을 해석할 때, 제가 하고 있던 방법은integerValuenero 문자열로부터, 이것은 나에게 불필요한 NSNumber를 준다.0내가 정말로 0이길 바랐을 때.

이전:

// 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

사용하기 전에 JSON 생성 사전 또는 배열에서 늘을 제거하는 몇 가지 카테고리 메서드를 작성했습니다.

@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 구문 분석 libs에 기본적으로 이 동작이 있으면 좋을 것입니다. NSNull로 포함시키는 것보다 늘 개체를 생략하는 것이 거의 항상 null 개체를 생략하는 것이 좋습니다.

또 다른 방법은

-[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"];

바로 그거야

언급URL : https://stackoverflow.com/questions/9137920/nsnull-handling-for-nsmanagedobject-properties-values

반응형