2012-01-20 10 views
6

Çevrimdışı kullanım için kaydetmek istediğim tonlarca nesneye sahibim. Şu anda, çevrimdışı olması için dosyaya kodlanmış veriler ve kodlanmış veriler için NSCoder uyumlu sınıflar oluşturuyorum. Kolay yolu yapmak için NSCoder etkin sınıf

Yani .h ben nesneleri tanıtmak:
- (id) initWithCoder: (NSCoder *)coder { 
    if (self = [super init]) { 
     [self setMyObject: [coder decodeObjectForKey:@"myObject"]]; 
    } 
} 

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

Yani sınıf alıcı ve ayarlayıcı ile sadece kukla depolama alanı:
@interface MyClass : NSObject<NSCoding>{ 
NSNumber* myObject;} 
@property(nonatomic,retain) NSNumber* myObject; 

Ve .m içinde

Ben INITs olun. Kod çözme/kodlama yapmak için daha iyi bir yol var mı. Kodlama ve kod çözme için bir şekilde @dynamic veya Anahtar-değer kodlamasını kullanabilir miyim? Temel olarak, program başlatıldığında sınıftaki tüm değişkenlerin dosyaya kaydedilmesini ve nesneye geri dönmesini istiyorum. Bu yaklaşım işe yarar, ancak tüm sınıfları oluşturmak zaman ve çaba gerektirir.

cevap

43

Evet, bunu otomatik olarak yapabilirsiniz.

- (NSArray *)propertyKeys 
{ 
    NSMutableArray *array = [NSMutableArray array]; 
    Class class = [self class]; 
    while (class != [NSObject class]) 
    { 
     unsigned int propertyCount; 
     objc_property_t *properties = class_copyPropertyList(class, &propertyCount); 
     for (int i = 0; i < propertyCount; i++) 
     { 
      //get property 
      objc_property_t property = properties[i]; 
      const char *propertyName = property_getName(property); 
      NSString *key = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]; 

      //check if read-only 
      BOOL readonly = NO; 
      const char *attributes = property_getAttributes(property); 
      NSString *encoding = [NSString stringWithCString:attributes encoding:NSUTF8StringEncoding]; 
      if ([[encoding componentsSeparatedByString:@","] containsObject:@"R"]) 
      { 
       readonly = YES; 

       //see if there is a backing ivar with a KVC-compliant name 
       NSRange iVarRange = [encoding rangeOfString:@",V"]; 
       if (iVarRange.location != NSNotFound) 
       { 
        NSString *iVarName = [encoding substringFromIndex:iVarRange.location + 2]; 
        if ([iVarName isEqualToString:key] || 
         [iVarName isEqualToString:[@"_" stringByAppendingString:key]]) 
        { 
         //setValue:forKey: will still work 
         readonly = NO; 
        } 
       } 
      } 

      if (!readonly) 
      { 
       //exclude read-only properties 
       [array addObject:key]; 
      } 
     } 
     free(properties); 
     class = [class superclass]; 
    } 
    return array; 
} 

Sonra buradan NSCoder yöntemleri şunlardır::

- (id)initWithCoder:(NSCoder *)aDecoder 
{ 
    if ((self = [self init])) 
    { 
     for (NSString *key in [self propertyKeys]) 
     { 
      id value = [aDecoder decodeObjectForKey:key]; 
      [self setValue:value forKey:key]; 
     } 
    } 
    return self; 
} 

- (void)encodeWithCoder:(NSCoder *)aCoder 
{ 
    for (NSString *key in [self propertyKeys]) 
    { 
     id value = [self valueForKey:key]; 
     [aCoder encodeObject:value forKey:key]; 
    } 
} 

#import <objc/runtime.h> 
#import <objc/message.h> 

Şimdi özellik adlarını almak için alt düzey yöntemlerini kullanır bu yöntemi ekleyin: İlk önce sınıfa bunlar ithal

Bu konuda biraz dikkatli olmalısınız.

  1. Bu vb sayılar, bool değerlerden oluşan, nesneler, kalan binalar için çalışacaktır, ancak özel yapılar çalışmaz: Aşağıdaki uyarılar vardır. Ayrıca, sınıfınızdaki özelliklerden herhangi biri, kendilerini desteklemeyen nesneler NSCoding'i destekliyorsa, bu işe yaramaz.

  2. Bu yalnızca ivarlar değil sentezlenen özellikler ile çalışır.

Bunu kodlayan veya daha fazla incelikle bir sorun işlemek için setValueForUndefinedKey yöntemi geçersiz önce encodeWithCoder bir değerin türünü kontrol ederek hata işleme ekleyebilirsiniz.

GÜNCELLEME: Bir kütüphaneye kadar bu yöntemleri sarılmış ettik

: https://github.com/nicklockwood/AutoCoding - kütüphanesi yüzden herhangi sınıf kaydedilebilir veya yüklenebilir NSObject bir kategori olarak bu yöntemleri uygulayan ve aynı zamanda miras kodlama için destek ekler orijinal cevabımın işlemediği özellikler.

GÜNCELLEME 2:

Ben doğru kalıtsal başa ve özelliklerini salt okunur cevabını güncelledik.

+0

Harika bir cevap için teşekkürler, bu benim amacım için mükemmel. Size bir oy vereceğim, ancak yeterli saygınlığım yok .. – MapaX

+0

Kodda küçük bellek sızıntısı var. Şunları eklemelisiniz: free (properties); PropertyKeys yöntemine . – MapaX

+0

İyi bir çağrı - Ben düzeltdim. –

İlgili konular