【问题标题】:Saving Array to Plist file that contains Custom Objects iPhone将数组保存到包含自定义对象 iPhone 的 Plist 文件
【发布时间】:2011-12-28 01:23:49
【问题描述】:

我有一个从 NSObject 继承的名为 XYZ 的类和一个包含 XYZ 对象的数组。我需要将此数组写入到文档目录的 plist 文件中。尝试 [array writeToFile....] 后,我发现 writeToFile 失败,因为该数组包含 XYZ 类的自定义对象。

可能的解决方案是将对象转换为 NSData。实现这一目标的不同方法是什么?我发现 NSCoding 是合适的,但不明白如何使用它。任何帮助将不胜感激。

【问题讨论】:

    标签: iphone objective-c ios cocoa-touch nsdocumentdirectory


    【解决方案1】:

    在为自定义类实现encodeWithCoder:initWithCoder:后,这里是如何读写:

    写:

    NSError  *error;
    NSData* archiveData = [NSKeyedArchiver archivedDataWithRootObject:yourClassInstance];
    [archiveData writeToFile:filePath options:NSDataWritingAtomic error:&error];
    

    阅读:

    NSData *archiveData = [NSData dataWithContentsOfFile:filePath];
    YourClass *yourClassInstance = (NSArray*)[NSKeyedUnarchiver unarchiveObjectWithData:archiveData];
    

    【讨论】:

    • 对于删除特定对象,怎么做?
    【解决方案2】:

    使您的 XYZ 类符合 NSCoding 协议确实非常适合您正在尝试做的事情。为此,请将 NSCoding 协议添加到类的接口声明中:

    @interface XYZ <NSCoding>
    

    然后,您需要在您的实现中实现 encodeWithCoder: 和 initWithCoder:。 “使用编码器编码”意味着“获取对象的当前状态,并将其打包到一个称为“编码器”的通用对象中”。 “Init with coder”的意思是“给定一个已经打包好的编码器对象,用打包到编码器中的数据来配置自己”。在这两种方法中,“编码器”都是NSCoder 的一个实例,它有一个相当简单的接口用于编码(“打包”)和解码(“解包”)基本类型。

    这是一个示例实现:

    @implementation XYZ
    - (id)initWithCoder:(NSCoder*)encoder
    {
        self = [self init];
    
        if (self)
        {
            self.myIntProperty = [encoder decodeIntForKey:@"myInt"];
        }
    
        return self;
    }
    
    – (void)encodeWithCoder:(NSCoder*)decoder
    {
        [decoder encodeInt:self.myIntProperty forKey:@"myInt"];
    }
    
    @end
    

    【讨论】:

      【解决方案3】:

      这很简单。对于给定的类Foo

      #import <Foundation/Foundation.h>
      
      @interface Foo : NSObject <NSCoding> {
          NSArray* bar_;
          NSUInteger baz_;
      }
      
      @property (nonatomic, retain) NSArray *bar;
      @property (nonatomic, assign) NSUInteger baz;
      
      @end
      

      要符合NSCoding 协议,您所要做的就是实现initWithCoder:decodeWithCoder 消息:

      #import "Foo.h"
      
      @implementation Foo
      @synthesize bar = bar_;
      @synthesize baz = baz_;
      
      #pragma mark - NSCoding
      
      - (void)encodeWithCoder:(NSCoder *)encoder  {
          [encoder encodeObject:self.bar forKey:@"bar"];
          [encoder encodeInteger:self.baz forKey:@"baz"];
      }
      
      - (id)initWithCoder:(NSCoder *)decoder  {
          if ((self = [super init])) {
              self.bar = [decoder decodeObjectForKey:@"bar"];
              self.baz = [decoder decodeIntegerForKey:@"baz"];
          }
          return self;
      }
      
      - (void) dealloc {
      
          [bar_ release];
          [super dealloc];    
      }
      
      @end
      

      【讨论】:

        【解决方案4】:

        Ray Wenderlich's blog 上有一个非常好的教程,它解释了如何使用 NSCoding。

        您只需在您的像这样尊重 NSCoding 协议的对象:

        // Header
        @interface AnObject: NSObject <NSCoding>
        
        // Implementation
        - (void) encodeWithCoder:(NSCoder *)encoder {
            [encoder encodeObject:ivar1 forKey:@"ivar1"];
            [encoder encodeFloat:ivar2 forKey:@"ivar2"];
        }
        
        - (id)initWithCoder:(NSCoder *)decoder {
            self = [super initWithCoder:coder];
            ivar1 = [[coder decodeObjectForKey:@"ivar1"] retain];
            ivar2 = [[coder decodeObjectForKey:@"ivar2"] retain];
            return self;
        }
        

        您也可以查看官方文档here

        【讨论】:

        • 我在每一行的 - (id)initWithCoder:(NSCoder *)decoder 中遇到内存泄漏。你知道可能的原因是什么吗? (我的 iVar1 和 ivar2 是字符串)
        • 你在dealloc方法中释放了吗?
        • @YannickL.hello,我想问一下NSCoding 的这些东西是否值得,或者更好地停在NSDictionary 上,例如您上面编写的代码?是否有任何选择标准,或者这只是一个品味问题?如果是这样,资源成本如何,什么更便宜?也许这是一个完整问题的主题,但在理论空间中它很安静,所以我将非常感谢您在这里回答或编辑您的问题。谢谢。
        • @flinth 我认为就设计模式而言,使用NSCoding 协议比使用NSDictionary 更好。使用NSDictionary 意味着创建了一个新对象,并且您无法移交序列化。对于性能,您可以查看此链接:developer.apple.com/library/mac/documentation/Cocoa/Conceptual/….
        【解决方案5】:

        您需要实现两个方法:-initWithCoder:-encodeWithCoder:。阅读NSCoding 文档;它们是非常直接的方法。您基本上想使用与其名称相对应的键来编码/解码您的实例变量。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-02
          • 2012-01-18
          • 1970-01-01
          • 2012-05-19
          • 2016-12-04
          • 1970-01-01
          相关资源
          最近更新 更多