NSUserDefaults, NSMutableDictionary'yi iOS'ta neden kaydedemedi?


145

Bir NSMutableDictionarynesneyi içine kaydetmek istiyorum NSUserDefaults. Anahtar tipi NSMutableDictionaryIS NSString, değer türüdür NSArray, ki uygular nesnenin bir listesini ihtiva eden NSCoding. Belge başına NSStringve NSArrayher ikisi de uygundur NSCoding.

Bu hatayı alıyorum:

[NSUserDefaults setObject: forKey:]: NSCFDictionary sınıfının .... özellik dışı değerini ekleme girişimi.

Yanıtlar:


230

Kaydetmeden önce bir alternatif buldum , ile biten kök nesneyi ( NSArraynesneyi) kullanarak NSKeyedArchiverkodluyorum NSData. Daha sonra UserDefaults'u kullanarak NSData.

Verilere ihtiyacım olduğunda, okudum ve nesneye geri dönüştürmek için NSDatakullanıyorum .NSKeyedUnarchiverNSData

Biraz külfetli, çünkü NSDataher seferinde dönüşüme / dönüşüme ihtiyacım var, ama işe yarıyor.

İşte istek başına bir örnek:

Kayıt etmek:

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

Yük:

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

Dizideki öğe uygular

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

Daha sonra uygulamasında CommentItemiki yöntem sağlar:

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

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

Daha iyi bir çözümü olan var mı?

Herkese teşekkürler.


4
Paylaşabileceğiniz bir kod örneğiniz var mı, bunu postada yapmaya çalışıyorum (537044) ama neşe duymadan
Anthony Main

Bu benim için güzel çalıştı. Bazı anahtarların dizge olmadığı NSDictionary nesnelerinin NSArrayını kodlamaya çalışıyordum. NSArray üzerinde NSKeyedArchiver ve Unarchiver kullanmak, "Özellik dışı değer girmeye çalış" hatasından kurtuldu.
John Wright

Yüklenen nesneyi ne zaman bırakmam gerekir? Tahsis çağrılmadı, bu yüzden otomatik olarak yayımlandığını varsayabilirim?
Marc

7
kaydetmek için [varsayılanlar senkronize et] eklememiz gerekebilir
thanhbinh84

Burada yayınlanan çözüm bir süre işe yarayabilir, ancak sınıfı kaldırmaya veya değiştirmeye karar verdiğinizde kendinizi bir karmaşa içinde bulacaksınız. Daha iyi bir çözüm, nesnenizin NSNumber, Strings, vb. Kullanarak durumunu bir sözlüğe yazmasını sağlamak ve ardından bunu saklamaktır. Geleceğin kanıtı.
Tom Andersen

105

Bir nesneyi kullanıcı varsayılanlarında kaydediyorsanız, tüm nesneler, özyinelemeli olarak tamamen aşağıya doğru özellik listesi nesneleri olmalıdır. NSCoding'e uymak burada hiçbir şey ifade etmez - NSUserDefaultsonları otomatik olarak kodlamaz NSData, bunu kendiniz yapmanız gerekir. "Uygulayan nesne listeniz NSCoding" özellik listesi nesneleri olmayan nesneler anlamına geliyorsa, kullanıcı varsayılanlarına kaydetmeden önce bunlarla bir şeyler yapmanız gerekir.

Özellik listesi sınıfları vardır Bilginize NSDictionary, NSArray, NSString, NSDate, NSData, ve NSNumber. NSMutableDictionaryKullanıcı tercihlerine göre değiştirilebilir alt sınıflar (gibi ) yazabilirsiniz, ancak okuduğunuz nesneler her zaman değişmez olacaktır.


61
Anahtarlar NSStrings ise, bir NSDictionary yalnızca bir özellik listesi nesnesi olduğunu da belirtmeliyim. Genelde diğer nesneleri sözlük anahtarları olarak kullanabilirsiniz, ancak özellik listelerinin gerekli olduğu yerlerde anahtarlar dizeler olmalıdır.
Tom Harrington

NSURL'yi bir NSDictionary içinde bir nesne olarak saklamak ve onu NSUserDefaults'da saklamak istediğimde aynı problemle karşılaştım. Çalıştığından daha çok NSString'e dönüştürmek zorunda kaldım.
NicTesla

1
Harika! Benim durumumda, NSNumber'ı kullanıcı varsayılanlarında NSDictionary anahtarı olarak kullanmaya çalıştım. Bunu bir NSString olarak değiştirmem gerekiyor.
Joey

1
Bu tür gecikmiş davranış, deneyimsiz kodlayıcıların doğru veri nesneleri yapmak yerine tüm veri modellerini sözlük olarak yazmalarına yol açar? Apple için, obj-c'nin iç gözlemi olduğu ve bizim için boks ve kutudan çıkarma işleriyle ilgilendiği gerçeğini kullanan temel sınıfları yazmak Apple için ne kadar zor olabilir?
ArtOfWarfare

14

Tüm anahtarlarınız sözlükte NSStringmi? Sözlüğü bir mülk listesine kaydetmek için olmaları gerektiğini düşünüyorum.


1
anahtarlar NSString'dir. ancak değer, NSCoding'i uygulayan özelleştirilmiş bir sınıf olan NSArray'dir. Görünüşe göre, UserDefaults NSCoding'i dikkate almıyor, yalnızca 6 tür sınıfı desteklediği için çözüm çalışmıyor.
BlueDolphin

8

En Basit Cevap:

NSDictionarySadece bir Plist nesne ise, tuşlar NSStrings vardır . Yani, "Anahtarı" olduğu gibi NSStringsaklayın stringWithFormat.


Çözüm :

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

Faydaları:

  1. String-Value ekleyecektir .
  2. Değişken Değeriniz olduğu zaman Boş Değer katacaktır NULL.

2
Benzer bir sorun yaşadım: Anahtarlarım NSNumber'lardı ve görünüşe göre plist sözlüklerinin anahtarlarında izin verilmiyor.
Mark Pauley

5

NSCodingProtokolü uygulamayı düşündünüz mü ? Bu, iPhone'da NSCoding. Öncelikle NSCodingsınıfınıza eklemeniz gerekir .

İşte bir örnek:

Bu .h dosyasındadır

@interface GameContent : NSObject <NSCoding>

O zaman NSCoding Protokolünün iki yöntemini uygulamanız gerekecektir.

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

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

Daha fazla bilgi için NSCoder'deki belgelere bakın. Bu, uygulama kapatılırsa uygulamanın durumunu iPhone'a kaydetmem ve tekrar açıldığında durumuna geri yüklemem gereken projelerim için gerçekten kullanışlı oldu.

Anahtar, protokolü arayüze eklemek ve ardından parçası olan iki yöntemi uygulamaktır NSCoding.

Umarım bu yardımcı olur!


0

Daha iyi bir çözüm yok. Başka bir seçenek de kodlanmış nesneyi diske kaydetmek olabilir - ama bu aynı şeyi yapıyor. Her ikisi de, geri istediğinizde kodu çözülen NSData ile sonuçlanır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.