Created
August 19, 2012 20:16
-
-
Save indragiek/3397389 to your computer and use it in GitHub Desktop.
Simple Cocoa state restoration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// SNRRestorationManager.h | |
// Sonora | |
// | |
// Created by Indragie Karunaratne on 2012-08-19. | |
// | |
#import <Foundation/Foundation.h> | |
@protocol SNRRestorableState <NSObject> | |
- (void)encodeRestorableStateWithArchiver:(NSKeyedArchiver *)archiver; | |
- (void)decodeRestorableStateWithArchiver:(NSKeyedUnarchiver *)unarchiver; | |
@end | |
@interface SNRRestorationManager : NSObject | |
@property (nonatomic, strong, readonly) NSSet *restorableObjects; | |
+ (instancetype)sharedManager; | |
- (void)registerRestorationObject:(id<SNRRestorableState>)object; | |
- (void)deregisterRestorationObject:(id<SNRRestorableState>)object; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// SNRRestorationManager.m | |
// Sonora | |
// | |
// Created by Indragie Karunaratne on 2012-08-19. | |
// | |
#import "SNRRestorationManager.h" | |
/* This category can be obtained here: <https://github.com/andymatuschak/NSObject-AssociatedObjects> */ | |
#import "NSObject+AssociatedObjects.h" | |
static void* const kSNRRestorationHasRestoredKey = "snr_hasRestored"; | |
@interface SNRRestorationManager () | |
// Notifications | |
- (void)encodeRestorableState; | |
- (void)decodeRestorableState; | |
- (void)applicationDidLaunch; | |
// Restoration | |
- (void)restoreStateForObject:(id<SNRRestorableState>)object; | |
// Locations | |
- (NSString *)restorationStatePath; | |
@end | |
@implementation SNRRestorationManager { | |
NSMutableSet *_restorableObjects; | |
NSKeyedUnarchiver *_lastUnarchiver; | |
} | |
@synthesize restorableObjects = _restorableObjects; | |
+ (instancetype)sharedManager | |
{ | |
static SNRRestorationManager *manager; | |
static dispatch_once_t token; | |
dispatch_once(&token, ^{ | |
manager = [[self alloc] init]; | |
}); | |
return manager; | |
} | |
- (id)init | |
{ | |
if ((self = [super init])) { | |
_restorableObjects = [NSMutableSet set]; | |
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; | |
[nc addObserver:self selector:@selector(encodeRestorableState) name:NSApplicationDidResignActiveNotification object:nil]; | |
[nc addObserver:self selector:@selector(encodeRestorableState) name:NSApplicationWillTerminateNotification object:nil]; | |
[nc addObserver:self selector:@selector(applicationDidLaunch) name:NSApplicationDidFinishLaunchingNotification object:nil]; | |
} | |
return self; | |
} | |
- (void)registerRestorationObject:(id<SNRRestorableState>)object | |
{ | |
[_restorableObjects addObject:object]; | |
[self restoreStateForObject:object]; | |
} | |
- (void)deregisterRestorationObject:(id<SNRRestorableState>)object | |
{ | |
[_restorableObjects removeObject:object]; | |
} | |
- (void)applicationDidLaunch | |
{ | |
[self decodeRestorableState]; | |
} | |
#pragma mark - Notifications | |
- (void)encodeRestorableState | |
{ | |
if (!_lastUnarchiver) { return; } | |
NSMutableData *data = [NSMutableData data]; | |
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; | |
for (id<SNRRestorableState> object in self.restorableObjects) { | |
[object encodeRestorableStateWithArchiver:archiver]; | |
} | |
[archiver finishEncoding]; | |
[data writeToFile:[self restorationStatePath] atomically:YES]; | |
} | |
- (void)decodeRestorableState | |
{ | |
NSData *data = [NSData dataWithContentsOfFile:[self restorationStatePath]]; | |
if (data) { | |
if (_lastUnarchiver) { [_lastUnarchiver finishDecoding]; } | |
_lastUnarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; | |
for (id<SNRRestorableState> object in self.restorableObjects) { | |
[self restoreStateForObject:object]; | |
} | |
} | |
} | |
- (void)restoreStateForObject:(id<SNRRestorableState>)object | |
{ | |
if (_lastUnarchiver && ![[(NSObject*)object associatedValueForKey:kSNRRestorationHasRestoredKey] boolValue]) { | |
[object decodeRestorableStateWithArchiver:_lastUnarchiver]; | |
[(NSObject*)object associateValue:[NSNumber numberWithBool:YES] withKey:kSNRRestorationHasRestoredKey]; | |
} | |
} | |
#pragma mark - Locations | |
- (NSString *)restorationStatePath | |
{ | |
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); | |
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory(); | |
NSString *bundleName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; | |
NSString *path = [basePath stringByAppendingPathComponent:bundleName]; | |
return [path stringByAppendingPathComponent:@"state"]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment