20

私はこの声明を持っています:

 [custData setObject: [rs stringForColumnIndex:2]  forKey: @"email"];

[rs stringForColumnIndex:2]SQLite3 d/b から取得した値はですnil。アプリがクラッシュして、次のエラーが表示されます。

NSCFDictionary setObject:forKey:]: attempt to insert nil value (key: email)'

これを防ぐ方法はありますか?(? の設定のようにNSMutableDictionary)

更新:これは私が最終的にやったことです:

[custData setObject: ([rs stringForColumnIndex:2] != nil? [rs stringForColumnIndex:2]:@"") forKey: @"email"];
4

3 に答える 3

38

「プレーン」が受け入れられない状況で sを表すために特別に作成された、 と呼ばれる非nilオブジェクトがあります。をオブジェクトに置き換えると、それらが取得されます。ただし、外出先で確認する必要があります。NSNullnilnilnil[NSNull null]NSDictionaryNSNull

これは、設定されていない値と に設定されている値を区別する必要がある場合にのみ重要であることに注意してくださいnil。コードが欠損値を として解釈nilできるようなものである場合は、まったく使用する必要はありませんNSNull

于 2012-06-01T20:16:42.467 に答える
5

純粋な NSMutableDictionary では不可能であり、ほとんどの場合、nil 値を辞書に変換する[NSNull null]か、単に辞書から除外する必要があります。ただし、(ごくまれに) nil 値を許可すると便利な場合があり、そのような場合は、カスタム コールバックで CFMutableDictionary を使用できます。

このようにすれば、CFDictionarySetValueや などのすべてのアクセスに CoreFoundation API を使用することをお勧めしますCFDictionaryGetValue

ただし、何をしているのかわかっている場合は、無料のブリッジングを使用して、その CFMutableDictionary を NSMutableDictionary または NSDictionary にキャストできます。これは、NSDictionary を受け入れるヘルパーがたくさんあり、それらを修正した nil 対応の辞書で使用したい場合に便利です。(もちろん、ヘルパーが nil 値に驚いていないことを確認してください。)

ブリッジングを行う場合は、次の点に注意してください。

1) NSMutableDictionary セッターは、ブリッジする前に nil 値でエラーを発生させるため、CFDictionarySetValue を使用して nil になる可能性のある値を設定する必要があります。

2) 技術的には、ここで NSMutableDictionary の契約に違反しており、問題が発生する可能性があります (たとえば、将来の OS アップデートで)

3) ディクショナリで nil 値を見つけると、多くのコードが非常に驚くでしょう。ブリッジされたフランケンディクショナリのみを、制御するコードに渡す必要があります

ブリッジされた CFDictionary が NSDictionary と異なる動作をする理由の説明については、無料のブリッジに関するとんでもない魚の投稿を参照してください。

例:

#import <Foundation/Foundation.h>

const void *NullSafeRetain(CFAllocatorRef allocator, const void *value) {
    return value ? CFRetain(value) : NULL;
}
void NullSafeRelease(CFAllocatorRef allocator, const void *value) {
    if (value)
        CFRelease(value);
}
const CFDictionaryValueCallBacks kDictionaryValueCallBacksAllowingNULL = {
    .version = 0,
    .retain = NullSafeRetain,
    .release = NullSafeRelease,
    .copyDescription = CFCopyDescription,
    .equal = CFEqual,
};

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        CFMutableDictionaryRef cfdictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kDictionaryValueCallBacksAllowingNULL);
        CFDictionarySetValue(cfdictionary, @"foo", @"bar");
        CFDictionarySetValue(cfdictionary, @"boz", nil);

        NSMutableDictionary *dictionary = CFBridgingRelease(cfdictionary);
        NSLog(@"dictionary[foo] = %@", dictionary[@"foo"]);
        NSLog(@"dictionary[foo] = %@", dictionary[[@"fo" stringByAppendingString:@"o"]]);
        NSLog(@"dictionary[boz] = %@", dictionary[@"boz"]);
        NSLog(@"dictionary = %@", dictionary);
        NSLog(@"(dictionary isEqualTo: dictionary) = %d", [dictionary isEqualToDictionary:dictionary]);
    }
    return 0;
}

出力:

dictionary[foo] = bar
dictionary[foo] = bar
dictionary[boz] = (null)
dictionary = {
    boz = (null);
    foo = bar;
}
(dictionary isEqualTo: dictionary) = 1
于 2013-07-19T05:00:47.710 に答える
0

NSDictionaryからまだ設定されていない可能性がある値を設定する必要がありましたNSUserDefaults

私がしたことは、値をstringwithFormat呼び出しでラップすることでした。どちらの値もまだ設定されていないため、null から開始します。呼び出しなしで実行するstringwithFormatと、アプリがクラッシュします。だから私はこれを行い、私の状況ではうまくいきました。

-(NSDictionary*)userDetailsDict{
NSDictionary* userDetails = @{
                              @"userLine":[NSString stringWithFormat:@"%@",[[NSUserDefaults standardUserDefaults]stringForKey:kSelectedLine] ],
                              @"userDepot":[NSString stringWithFormat:@"%@",[[NSUserDefaults standardUserDefaults]stringForKey:@"kSelected Duty Book"]]
                              };

return userDetails;
}
于 2015-04-07T09:14:42.667 に答える