35

my のプロパティの値を設定しています。NSManagedObjectこれらの値はNSDictionary、JSON ファイルから適切にシリアル化されたものから取得されています。私の問題は、値が の場合[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そして、1行のソリューションはなくなりました。

@try @catch ブロックを作成しようとしましたが、最初の値がキャッチされるとすぐに @try ブロック全体をジャンプし、次のプロパティは無視されます。

[NSNull null]これを処理する、またはおそらくこれを完全に異なるが簡単にするより良い方法はありますか?

4

5 に答える 5

67

これをマクロでラップすると、少し簡単になるかもしれません。

#define NULL_TO_NIL(obj) ({ __typeof__ (obj) __obj = (obj); __obj == [NSNull null] ? nil : obj; })

次に、次のようなものを書くことができます

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

または、辞書を前処理して、管理対象オブジェクトに詰め込もうとする前に、すべてをに置き換えることNSNullもできます。nil

于 2012-02-04T02:58:54.237 に答える
8

わかりました、私は今朝、良い解決策で目が覚めました。これはどうですか:

可変配列と辞書を受け取るオプションを使用して、JSON をシリアル化します。

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

[NSNull null]leafDict から値を持つ一連のキーを取得します。

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)ornilではなく、自動的に<null>orになり[NSNull null]ます。

NSNumberFormatterこれとは関係ありませんが、文字列を NSNumber に解析するときにa を使用する方が良いことにも気付きました。私が行っていた方法は nil 文字列から取得していました。これにより、実際に nil にしたかったときにintegerValue、望ましくない NSNumber が得られます。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
于 2012-02-04T16:15:10.630 に答える
1

使用する前に、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 解析ライブラリがデフォルトでこの動作を備えているとよいでしょう。ほとんどの場合、null オブジェクトを NSNull として含めるよりも、null オブジェクトを省略する方が望ましいです。

于 2012-02-04T03:25:38.277 に答える
0

別の方法は

-[NSObject setValuesForKeysWithDictionary:]

このシナリオでは、次のことができます

[fight setValuesForKeysWithDictionary:dict];

ヘッダー NSKeyValueCoding.h では、「値が NSNull であるディクショナリ エントリは、-setValue:nil forKey:keyメッセージが受信者に送信されることになります。

唯一の欠点は、ディクショナリ内のキーをレシーバー内のキーに変換する必要があることです。すなわち

dict[@"winnerID"] = dict[@"winner"];
[dict removeObjectForKey:@"winner"];
于 2014-02-10T07:19:37.237 に答える