Objective-Cでシンプルにシリアライズ(永続化)して、簡単にファイルとして保存・復元するカテゴリを作りました。

Objective-Cでシンプルにシリアライズするカテゴリを作りました。

まずはじめに断っておきます。
これは、めちゃくちゃ単純なカテゴリです。

しかしNSObjectのサブクラスであれば、どんなオブジェクトでも自身を簡単に保存できちゃうので、結構使っています。

クラス名をディレクトリのパスに変換して、クラス固有のパスを生成し、それとキーを組み合わせたファイルパスに保存する仕組みになっているので同じクラスのインスタンスかつ同じキーを使うことで、同じデータを保存(書き出し)&復元(読み込み)するカテゴリです。

ソースコードはこちらです。
JAGSerialize

使い方

例えば、NSObjectのサブクラスCustomObjectClassがあるとします。
そのオブジェクトが使うデータは、NSArrayのインスタンス変数で保持しているとします。

@interface CustomObjectClass ()

@property (nonatomic,readwrite)NSArray *dataArray;

@end

それを保存する場合は、saveWithData:forKeyメソッドでそのインスタンス変数と固有のキーを指定してください。
一応バックグラウンド用のsaveWithData:forKey:completionBlock:メソッドもあります。

- (void)_save{

    [self saveWithData:_dataArray forKey:@"data"];
}

- (void)_saveBackground{

    [self saveWithData:_dataArray forKey:@"data" completionBlock:^(BOOL success) {
        if () {
            NSLog(@"Success");
        } else {
            NSLog(@"Error");
        }
   }];
}

読み出すときは、loadDataForKeyメソッドで読み出します。
こちらもバックグラウンドで処理するloadDataForKey:completionBlock:メソッドがあります。

- (void)_load{

    _dataArray = [self loadDataForKey:@"data"];

    if (_dataArray) {

    } else {
        _dataArray = [NSArray new];
    }
}

- (void)_loadBackground{

    _dataArray = [self loadDataForKey:@"" completionBlock:^(id dataObject) {

    if (dataObject) {
        _dataArray = dataObject;
    } else {
        _dataArray = [NSArray new];
    }   

    }];
}

このような感じで簡単に使えるカテゴリです。

仕組み/実装

Documentsディレクトリにクラス名のディレクトリを作って、そこにクラス名+固有のキーをファイル名としたデータをNSKeyedArchiverarchiveRootObject:toFile:メソッドで保存するようにしています。
一応隠しファイルとしています。

- (BOOL)saveWithData:(id<NSCoding>)data forKey:(NSString *)key{

  NSString *fileName = [NSString stringWithFormat:@".%@-%@.dat",NSStringFromClass([self class])],key];

  NSString *archiveFilePath = [self _archiveFilePathWithDirectoryNameInDocumentsDirectory:[[NSString alloc]initWithFormat:@".%@",NSStringFromClass([self class])]
                                                                              fileName:fileName];
  if ( [NSKeyedArchiver archiveRootObject:data toFile:archiveFilePath] ) {

     return YES;
  } else {

      return NO;
  }
}

// Documentsディレクトリの中にディレクトリとファイル名を繋げたファイルパスを返す。
// ディレクトリがなければ新規作成する。
- (NSString *)_archiveFilePathWithDirectoryNameInDocumentsDirectory:(NSString *)dirName fileName:(NSString *)fileName{

 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
 NSString *documentsDirPath = [paths objectAtIndex:0];
 NSString *archiveDirPath = [documentsDirPath stringByAppendingPathComponent:dirName];

 NSFileManager *fileManager = [NSFileManager defaultManager];
 NSError *error;

 if (![fileManager fileExistsAtPath:archiveDirPath]) {

     if ( [fileManager createDirectoryAtPath:archiveDirPath
                withIntermediateDirectories:YES
                                 attributes:nil
                                      error:&error] ) {
          if (error) {
            NSLog(@"Error");
           }
       }
   }

    NSString *archiveFilePath = [archiveDirPath stringByAppendingPathComponent:fileName];

    return archiveFilePath;
}

読み出すときは、逆にNSKeyedUnarchiverunarchiveObjectWithFileメソッドで読みだしています。

ぼくは、毎回考えるのが面倒なのでクラス名のディレクトリを生成していますが、固有のディレクトリ名にしても良いと思います。

Githubにアップしましたので、自由に使ってください。

CocoaPodsをお使いの場合は、

pod 'JAGSerialize', :git => 'https://github.com/ryuiwasaki/JAGSerialize.git'

とPodsfileに書き加えてください。

これからも更新を続けていきますので、Feedlyへの登録をお願いします!

follow us in feedly

コメントを残す

メールアドレスが公開されることはありません。