如何将NSMutableArray(包含其他数组)保存到文件中

n.e*_*ind 3 iphone cocoa-touch objective-c nscoder

之前已经提出过,人们已经就如何做到这一点给出了非常好的指示,例如这里.

但是,如果我只想将一个NSMutableArray(包含另一个NSMutableArray的各种实例)保存到文件中,我想知道我是否真的需要使用NSCoder?我试过这个,但只收到一条错误信息:

    -(void)saveLibraryDat {

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents directory
    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"myLibrary.dat"];
    NSError *error;

    [myLibrary writeToFile:filePath atomically:YES];

    if (error) {
        NSLog(@"There was an error saving myLibrary.dat: %@", error);
    }

}
Run Code Online (Sandbox Code Playgroud)

我的错误信息:

2011-05-13 22:00:47.840 MoleNotes[15437:207] There was an error saving myLibrary.dat: (
    1,
    2
)
Run Code Online (Sandbox Code Playgroud)

所以我想我必须和NSCoder合作,对吧?如果是这样,我想知道如何解决这个问题.人们已经解释了如何使用类来完成此操作,但在我的情况下,我有一个NSMutableArray(myLibrary),其中包含类的各种实例.我是否必须在此类和NSMutableArray中实现NSCoder?

我像这样分配我的库:

    myLibrary = [[NSMutableArray alloc] init];
Run Code Online (Sandbox Code Playgroud)

然后添加一个名为NoteBook.m的类的实例,如下所示:

    NoteBook *newNoteBook = [[NoteBook alloc] init];
       newNoteBook.titleName = @"Notes"; // etc.

[myLibrary addObject:newNoteBook];
Run Code Online (Sandbox Code Playgroud)

那么我在哪里放置NSCoder命令呢?只进入我的NoteBook.m类?这会自动照顾myLibrary吗?

谢谢你的任何建议.


编辑:

所以我已经更新了我的代码,但我想最大的问题是我的NSMutableArray myLibrary包含了我设置的一个自定义类的几个实例(称为notebook).我为这个类(及其所有变量)设置了NSCoding,以便我可以保存并加载它.

现在我的应用程序完全正常,如果我在应用程序中创建NSMutableArray(即应用程序第一次启动,没有文件存在),而不是从磁盘加载它:

    -(void) setupLibrary {

    myLibrary = [[NSMutableArray alloc] init];

    NoteBook *newNoteBook = [[NoteBook alloc] init];

    newNoteBook.titleName = @"Notes"; 
/...
Run Code Online (Sandbox Code Playgroud)

如果我从磁盘加载它,它也可以正常工作:

-(void)loadLibraryDat {

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents directory
    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"myLibrary.dat"];

    myLibrary = [[NSMutableArray alloc] init];  
    myLibrary = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];

    if (!myLibrary) {
        // if it couldn't be loaded from disk create a new one
        NSLog(@"myLibrary.dat empty... set up new one");


        [self setupLibrary];
        } else { NSLog(@"Loading myLibrary.dat successful."); }

    }
Run Code Online (Sandbox Code Playgroud)

如果我在加载后记录我的库中包含的所有内容,一切都还可以.例如,以下工作完全正常:

    NSLog(@"%@", [[self.myLibrary objectAtIndex:0] titleName]); 
Run Code Online (Sandbox Code Playgroud)

但是,最大的问题是,如果任何其他方法试图访问myLibrary.例如,如果我从另一个方法调用相同的日志命令,应用程序将崩溃,我收到此错误消息:

    [NSCFString objectAtIndex:]: unrecognized selector sent to instance 0x4b38510
2011-05-14 14:09:10.490 Notes[17091:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString objectAtIndex:]: unrecognized selector sent to instance 0x4b38510'
Run Code Online (Sandbox Code Playgroud)

这听起来好像myLibrary已经以某种方式解除分配,但我不明白为什么.怎么会发生这种情况?我觉得我在NSCoding设置中做错了...因为如果我只是在代码中创建myLibrary,那么一切都很有效.只有当我从磁盘加载它时,应用程序才会崩溃.


这是课程设置:

  #import <Foundation/Foundation.h>

@interface NoteBook : NSObject <NSCoding> {

    NSString *titleName;

    NSString *fileName;
    NSMutableArray *tabTitles;
    NSMutableArray *tabColours;
    NSMutableArray *tabReference;   

}

@property (nonatomic, retain) NSString *titleName;

@property (nonatomic, retain) NSString *fileName;
@property (nonatomic, retain) NSMutableArray *tabTitles;
@property (nonatomic, retain) NSMutableArray *tabColours;
@property (nonatomic, retain) NSMutableArray *tabReference;

-(id)initWithCoder:(NSCoder *)aDecoder;
-(void)encodeWithCoder:(NSCoder *)aCoder;


@end


//
//  NoteBook.m

#import "NoteBook.h"


@implementation NoteBook

@synthesize titleName, fileName, tabTitles, tabColours, tabReference;

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super init];
    if (self) {
        self.titleName = [aDecoder decodeObjectForKey:@"titleName"];
        self.fileName = [aDecoder decodeObjectForKey:@"fileName"];
        self.tabTitles = [aDecoder decodeObjectForKey:@"tabTitles"];
        self.tabColours = [aDecoder decodeObjectForKey:@"tabColours"];
        self.tabReference = [aDecoder decodeObjectForKey:@"tabReference"];
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:titleName forKey:@"titleName"];
    [aCoder encodeObject:fileName forKey:@"fileName"];
    [aCoder encodeObject:tabTitles forKey:@"tabTitles"];
    [aCoder encodeObject:tabColours forKey:@"tabColours"];
    [aCoder encodeObject:tabReference forKey:@"tabReference"];
}

@end
Run Code Online (Sandbox Code Playgroud)

编辑:

我想我已经解决了......我忘了一点'自我'......这搞砸了所有这些并取消了我的图书馆:

    self.myLibrary = [NSKeyedUnarchiver
                   unarchiveObjectWithFile:filePath];

if (self.myLibrary == nil) {
    NSLog(@"myLibrary.dat empty... set up new one");
    [self setupLibrary];
} else { NSLog(@"Loading myLibrary.dat successful."); }
Run Code Online (Sandbox Code Playgroud)

Chu*_*uck 5

你的代码被破坏了."错误"变量未初始化且从未设置,因此当您检查它时,您只是看到随机垃圾数据.如果您想知道写入是否成功,请检查返回值writeToFile:atomically:.YES如果写入成功,NO如果不成功,那将是.

但是,NSArray的writeTo…方法是用于创建plist.如果非属性列表对象在您的数组中,则该方法不合适,并且您希望使用归档程序.做一些像[[NSKeyedArchiver archivedDataWithRootObject:myLibrary] writeToFile:writeToFile:filePath atomically:YES].

为了让你的对象符合NSCoding正确的,只是他们实施initWithCoder:encodeWithCoder:,和在这些方法中,使用NSCoder的存储方法来存储对象的实例变量(和检索方法,让他们回来了).