Нужна помощь в реализации initWithCoder и NSUnarchiver с одиночным - PullRequest
0 голосов
/ 06 февраля 2012

У меня проблемы с выяснением того, как заставить архивирование работать в приложении для iOS 5. У меня есть одноэлементный SessionStore, в который я хотел бы получить данные plist, если они существуют после инициализации SessionStore наследуется от NSObject и имеет один ivar, NSMutableArray * allSessions, который я хочу загрузить из файла plist. Вот SessionStore.m Не уверен, что проблема очевидна или вам нужна дополнительная информация ... спасибо! Nathan

#import "SessionStore.h"

static SessionStore *defaultStore = nil;

@implementation SessionStore

+(SessionStore *)defaultStore {
    if (!defaultStore) {
        // Load data.plist if it exists
        NSString *pathInDocuments = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"data.plist"];
    NSFileManager *fileManager = [[NSFileManager alloc] init];
    if ([fileManager fileExistsAtPath:pathInDocuments])
        defaultStore = [NSKeyedUnarchiver unarchiveObjectWithFile:pathInDocuments];   
    } else
        defaultStore = [[super allocWithZone:NULL] init]; 

    return defaultStore;
}


+(id)allocWithZone:(NSZone *)zone {
    return [self defaultStore];
}

-(id)init {
    if (defaultStore)
        return defaultStore;

    self = [super init];

    if (self)
        allSessions = [[NSMutableArray alloc] init];

    return self;
}

-(NSMutableArray *)allSessions {
    if (!allSessions) allSessions = [[NSMutableArray alloc] init];
    return allSessions;
}

-(void)setAllSessions:(NSMutableArray *)sessions {
    allSessions = sessions;
}

-(void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:allSessions forKey:@"All Sessions"];
}

-(id)initWithCoder:(NSCoder *)aDecoder {
    self = [SessionStore defaultStore];
    [self setAllSessions:[aDecoder decodeObjectForKey:@"All Sessions"]];
    return self;
}

В AppDelegate.m он сохраняет файл plist после завершения:

- (void)applicationWillTerminate:(UIApplication *)application
{
    // Save data to plist file
    NSString *pathInDocuments = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"data.plist"];

    [NSKeyedArchiver archiveRootObject:[SessionStore defaultStore] toFile:pathInDocuments];
}

1 Ответ

0 голосов
/ 06 февраля 2012

Обычно я делаю это, имея файл данных, в который я сохраняю вещи, когда мне нужно, и затем загружаю их обратно при инициализации объекта.Так что-то вроде этого:

@interface SessionStore
@property (nonatomic, copy) NSMutableArray *allSessions;

- (void)loadData;
- (void)saveData;
@end

static SessionStore *sharedInstance = nil;

static NSString *const kDataFilename = @"data.plist";

@implementation SessionStore

@synthesize allSessions = _allSessions;

#pragma mark -

+ (id)sharedInstance {
    if (sharedInstance == nil)
        sharedInstance = [[self alloc] init];
    return sharedInstance;
}


#pragma mark -

- (id)init {
    if ((self = [super init])) {
        [self loadData];
    }
    return self;
}


#pragma mark -

- (void)loadData {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *path = [documentsDirectory stringByAppendingPathComponent:kDataFilename];

    NSFileManager *fileManager = [NSFileManager defaultManager];
    if ([fileManager fileExistsAtPath:path]) {
        NSMutableData *theData = [NSData dataWithContentsOfFile:path];
        NSKeyedUnarchiver *decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];
        self.allSessions = [[decoder decodeObjectForKey:@"allSessions"] mutableCopy];
        [decoder finishDecoding];
    }

    if (!_allSessions) {
        self.allSessions = [[NSMutableArray alloc] initWithCapacity:0];
    }
}

- (void)saveData {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *path = [documentsDirectory stringByAppendingPathComponent:kDataFilename];

    NSMutableData *theData = [NSMutableData data];
    NSKeyedArchiver *encoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:theData];

    [encoder encodeObject:_allSessions forKey:@"allSessions"];
    [encoder finishEncoding];

    [theData writeToFile:path atomically:YES];
}

Затем, когда я захочу, я бы позвонил saveData, чтобы сохранить данные обратно на диск.Это может происходить каждый раз, когда allSessions изменяется, или только один раз, когда приложение завершает работу / переходит в фоновый режим.Это будет зависеть от того, как часто allSessions изменяется и насколько важно обеспечить сохранение данных.

Имейте в виду, что код для синглтона ни в коем случае не лучший - ищите здесьStackOverflow для обоснования использования GCD dispatch_once или аналогичного, если вы беспокоитесь о том, что sharedInstance может быть расой.

Я думаю, что это лучше, чем ваш метод, потому что вы пытаетесь сериализовать весь объект-одиночка, а неего содержание, которое, я думаю, немного легче понять, что происходит, и тогда сам синглтон обрабатывает всю загрузку и сохранение, а не выливает ваш NSKeyedArchiver в делегат приложения, как вы это сделали.

...