NSUserDefaultsがiOSでNSMutableDictionaryを保存できないのはなぜですか?


145

NSMutableDictionaryオブジェクトをに保存したいNSUserDefaults。のキータイプNSMutableDictionaryNSString、値タイプはNSArrayであり、実装するオブジェクトのリストが含まれていますNSCoding。ドキュメントごとにNSStringNSArray両方ともに準拠していNSCodingます。

このエラーが発生しています:

[NSUserDefaults setObject:forKey:]:NSCFDictionaryクラスの非プロパティ値を挿入しようとしました...

回答:


230

私は保存する前に、私はルートオブジェクト(エンコード、一つの代替を発見NSArray使用してオブジェクト)NSKeyedArchiver、との両端をNSData。次に、UserDefaultsを使用してを保存しNSDataます。

私は、データを必要とするとき、私は読み出しNSData、および使用がNSKeyedUnarchiver変換するNSDataオブジェクトに戻します。

NSData毎回変換する必要があるので少し面倒ですが、うまくいきます。

リクエストごとの1つの例を次に示します。

保存する:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *arr = ... ; // set value
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arr];
[defaults setObject:data forKey:@"theKey"];
[defaults synchronize];

負荷:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:@"theKey"];
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data];

配列の要素は実装します

@interface CommentItem : NSObject<NSCoding> {
    NSString *value;
}

次に、の実装でCommentItem、2つのメソッドを提供します。

-(void)encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeObject:value forKey:@"Value"];
}

-(id)initWithCoder:(NSCoder *)decoder
{
    self.value = [decoder decodeObjectForKey:@"Value"];
    return self;
}

誰かがより良い解決策を持っていますか?

みんな、ありがとう。


4
共有できるコードサンプルがありますか。私は投稿(537044)でこれを試みましたが、喜びはありませんでした
Anthony Main

これは私にとってはうまくいきました。一部のキーが文字列ではないNSDictionaryオブジェクトのNSArrayをエンコードしようとしました。NSArrayでNSKeyedArchiverおよびUnarchiverを使用するだけで、「プロパティ以外の値を挿入しようとしました」というエラーがなくなりました。
ジョンライト

ロードされたオブジェクトを解放する必要があるのはいつですか?割り当てが呼び出されなかったので、自動解放されたと思いますか?
マルク

7
保存するには[defaults synchronize]を追加する必要があるかもしれません
thanhbinh84 '19 / 09/19

ここに投稿された解決策はしばらくは機能するかもしれませんが、クラスを削除または変更することを決定すると、混乱に陥ります。より良い解決策は、オブジェクトにNSNumbers、文字列などを使用してその状態をディクショナリに書き込み、それを格納することです。将来の証拠。
トムアンデルセン、

105

オブジェクトをユーザーデフォルトに保存する場合、すべてのオブジェクトは、再帰的に、ずっと下にあるプロパティリストオブジェクトでなければなりません。NSCodingに準拠しても、ここでNSUserDefaultsは何も意味しません。自動的ににエンコードされNSDataないので、自分で行う必要があります。「実装NSCodingするオブジェクトのリスト」がプロパティリストオブジェクトではないオブジェクトを意味する場合、ユーザーデフォルトに保存する前に、それらを使用して何かを行う必要があります。

FYIプロパティリストクラスはNSDictionaryNSArrayNSStringNSDateNSData、とNSNumber。変更可能なサブクラス(などNSMutableDictionary)をユーザー設定に書き込むことができますが、読み取るオブジェクトは常に不変です。


61
また、キーがNSStringである場合、NSDictionaryはプロパティリストオブジェクトにすぎないことにも言及する必要があります。一般に、他のオブジェクトを辞書キーとして使用できますが、プロパティリストが必要な場合、キーは文字列でなければなりません。
トムハリントン

NSURLをオブジェクトとしてNSDictionaryに格納し、それをNSUserDefaultsに格納したいときに、同じ問題に遭遇しました。それが機能するよりも、NSStringに変更する必要がありました。
NicTesla、2011年

1
すごい!私の場合、ユーザーのデフォルトでNSNumberをNSDictionaryのキーとして使用しようとしました。NSStringに変更する必要があります。
Joey

1
そのような遅れた振る舞いは、適切なデータオブジェクトを作成するのではなく、経験の浅いコーダーがデータモデル全体をディクショナリとして作成することにつながります。Appleが、obj-cが内省的であり、ボクシングとアンボクシングを処理するという事実を利用するファウンデーションクラスを作成するのはどれほど大変なことでしょうか。
ArtOfWarfare 2013

14

すべてのキーは辞書にありますNSStringか?辞書をプロパティリストに保存するために必要です。


1
キーはNSStringです。ただし、値はNSArrayで、その要素はNSCodingを実装するカスタマイズされたクラスです。UserDefaultsは6種類のクラスしかサポートしていないため、ソリューションが機能していないようです。NSCodingは考慮されていません。
BlueDolphin 2009年

8

最も簡単な答え:

NSDictionaryキーがNSStringの場合は、plistオブジェクトのみです。したがって、と同様に「キー」保存します。NSStringstringWithFormat


解決 :

NSString *key = [NSString stringWithFormat:@"%@",[dictionary valueForKey:@"Key"]];

利点 :

  1. String-Valueを追加します。
  2. 変数の値がの場合、空の値が追加されますNULL

2
私は同様の問題を抱えていました:私のキーはNSNumbersでした。これは明らかにplist辞書のキーでは許可されていません。
マークポーリー2013

5

NSCodingプロトコルの実装を検討することを検討しましたか?これにより、で実装される2つのシンプルなメソッドを使用して、iPhoneでエンコードおよびデコードできますNSCoding。まずNSCoding、クラスにを追加する必要があります。

次に例を示します。

これは.hファイルにあります

@interface GameContent : NSObject <NSCoding>

次に、NSCodingプロトコルの2つのメソッドを実装する必要があります。

    - (id) initWithCoder: (NSCoder *)coder
    {
        if (self = [super init])
        {
               [self setFoundHotSpots:[coder decodeObjectForKey:@"foundHotSpots"]];
        }
        return self;
    }

    - (void) encodeWithCoder: (NSCoder *)coder
    {
           [coder encodeObject:foundHotSpots forKey:@"foundHotSpots"];
    }

詳細については、NSCoderのドキュメントをご覧ください。これは、アプリケーションが閉じている場合にiPhoneでアプリケーションの状態を保存し、アプリケーションが再びオンになったときの状態に戻す必要がある私のプロジェクトに非常に役立ちます。

重要なのは、プロトコルをインターフェイスに追加して、の一部である2つのメソッドを実装することですNSCoding

これが役に立てば幸いです!


0

これ以上の解決策はありません。もう1つのオプションは、コード化されたオブジェクトをディスクに保存することですが、同じことを行っています。どちらも最終的にNSDataになり、必要なときにデコードされます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.