3

これは以前に尋ねられており、人々はこれを行う方法について非常に良い指示を与えています、例えばここで

ただし、1つの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);
    }

}

私のエラーメッセージ:

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

だから私はNSCoderと一緒に仕事をしなければならないと思いますよね?もしそうなら、私はこれについてどうやって行くのか疑問に思いました。人々はクラスでこれを行う方法を説明しましたが、私の場合、クラスのさまざまなインスタンスを含むNSMutableArray(myLibrary)があります。このクラスとNSMutableArrayにNSCoderを実装する必要がありますか?

私は自分のライブラリを次のように割り当てます。

    myLibrary = [[NSMutableArray alloc] init];

次に、次のようにNoteBook.mというクラスのインスタンスを追加します。

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

[myLibrary addObject:newNoteBook];

では、NSCoderコマンドを正確にどこに配置すればよいでしょうか。私のNoteBook.mクラスにのみ?これは自動的にmyLibraryを処理しますか?

提案をありがとう。


編集:

コードを更新しましたが、大きな問題は、NSMutableArray myLibraryに、設定したカスタムクラス(ノートブックと呼ばれる)のインスタンスがいくつか含まれていることだと思います。このクラス(およびそのすべての変数)にNSCodingを設定して、保存してロードできるようにしました。

これで、ディスクからロードする代わりに、アプリでNSMutableArrayを作成した場合(つまり、アプリを初めて起動したときにファイルが存在しない場合)、アプリは完全に正常に機能します。

    -(void) setupLibrary {

    myLibrary = [[NSMutableArray alloc] init];

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

    newNoteBook.titleName = @"Notes"; 
/...

ディスクからロードすると、正常に動作します。

-(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."); }

    }

ライブラリをロードした後にライブラリに含まれているものをすべてログに記録しても、すべて問題ありません。たとえば、次は完全に正常に機能します。

    NSLog(@"%@", [[self.myLibrary objectAtIndex:0] titleName]); 

ただし、大きな問題は、他のメソッドがmyLibraryにアクセスしようとした場合です。たとえば、別のメソッドからまったく同じlogコマンドを呼び出すと、アプリがクラッシュし、次のエラーメッセージが表示されます。

    [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'

これは、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

編集:

私はそれを解決したと思います...私は少し「自己」を忘れました...それはそれをすべて台無しにしてmyLibraryの割り当てを解除しました:

    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."); }
4

2 に答える 2

5
于 2011-05-14T08:41:16.000 に答える
1

NSCoder is a protocol that your class must conform to in order to be archived to data/file. Works something like Serealizabe in Java.

Add conformance to the class header like this:

@interface NoteBook : NSObject <NSCoder> { // …

And then you must implement two methods:

-(id)initWithCoder:(NSCoder)decoder;
{
    self = [super initWithCoder:decoder];
    if (self) {
        _someIvar = [decoder decodeObjectForKey:@"someKey"];
        // And more init as needed…
    }
    return self;
}
-(void)encodeWithCoder:(NSCoder)coder;
{
   [super encodeWithCoder:coder];
   [coder encodeObject:_someIvar forKey@"someKey"];
   /// Etc…
}

I would also advice against using -[NSArray writeToFile:atomically:] since in work with property list compliant objects only, not coding compliant classes. The property list object are NSString, NSData, NSArray, or NSDictionary, NSDate, and NSNumber. The list can not be extended.

Instead use NSKeyedArchiver/NSKeyedUnarchiver. Almost as simple to use:

if (![NSKeyedArchive archiveRootObject:yourArrat toFile:path]) {
  // It failed.
}
于 2011-05-14T08:55:31.837 に答える