需要帮助使用单例实现 initWithCoder 和 NSUnarchiver

发布于 2025-01-02 19:06:20 字数 2083 浏览 1 评论 0原文

我无法弄清楚如何在 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];
}

I'm having trouble figuring out how to get the archiving to work in an iOS 5 app. I have a singleton SessionStore that I'd like to retrieve plist data if it exists upon initialization. SessionStore inherits from NSObject and has one ivar, an NSMutableArray *allSessions, which I want to load from the plist file. Here's the SessionStore.m Not sure if the problem is obvious or if you need more info... thanks! 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;
}

In AppDelegate.m it saves the plist file upon terminating:

- (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];
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

恬淡成诗 2025-01-09 19:06:20

我通常这样做的方法是拥有一个数据文件,在需要时将数据保存到其中,然后在对象初始化时将它们加载回来。就像这样:

@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 更改的频率以及确保保存数据的重要性。

请记住,单例的代码绝不是最好的 - 如果您担心 sharedInstancedispatch_once 或类似内容背后的推理。代码> 很花哨。

我认为这比你的方法更好,因为你试图序列化整个单例对象而不仅仅是它的内容,我认为这更容易理解正在发生的事情,然后单例本身处理所有加载和保存,而不是让你的NSKeyedArchiver 像您所做的那样溢出到应用程序委托中。

The way I usually do this is to have a data file which I save things to when I need to and then load them back up when the object is initialised. So something like this:

@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];
}

Then whenever I want to, I would call saveData to save the data back to disk. That might be every time allSessions changes, or just once when the app terminates / goes into the background. That would depend on how often allSessions changes and how crucial it is to ensure the data is saved.

Please bear in mind that the code there for the singleton is by no means the best - search around here on StackOverflow for reasoning behind using GCD dispatch_once or similar if you're worried about sharedInstance being racey.

I think this is better than your method because you are trying to serialise the whole singleton object rather than just its contents which I think is a bit easier to understand what's going on and then the singleton itself handles all the loading and saving rather than having your NSKeyedArchiver spill out into the app delegate like you have done.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文