备忘录模式
- 备忘录模式,什么都可以存!
- 先设计抽象接口,再去考虑实现细节
设计存储中心
MementoCenter
+ (void)saveMementoObject:(id <MementoCenterProtocol>)object withKey:(NSString *)key;
+ (id)mementoObjectWithKey:(NSString *)key;
指定存储接口(编码&解码)
MementoCenterProtocol
@protocol MementoCenterProtocol <NSObject>
@required
//编码
- (id)currentState;
//解码
- (void)recoverFromState:(id)state;
@end
数据类型
Apple
@interface Apple : NSObject <MementoCenterProtocol>
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSNumber *age;
@end
@implementation Apple
//编码
- (id)currentState {
return @{@"name": self.name,
@"age" : self.age};
}
//解码
- (void)recoverFromState:(id)state {
NSDictionary *data = state;
self.name = data[@"name"];
self.age = data[@"age"];
}
@end
实现存储机制
MementoCenter
+ (void)saveMementoObject:(id <MementoCenterProtocol>)object withKey:(NSString *)key {
NSParameterAssert(object);
NSParameterAssert(key);
// 获取data
id data = [object currentState];
NSData *tmpData = [FastCoder dataWithRootObject:data];
// 进行存储
if (tmpData) {
[[NSUserDefaults standardUserDefaults] setObject:tmpData
forKey:key];
}
}
+ (id)mementoObjectWithKey:(NSString *)key {
NSParameterAssert(key);
id data = nil;
NSData *tmpData = [[NSUserDefaults standardUserDefaults] objectForKey:key];
if (tmpData) {
data = [FastCoder objectWithData:tmpData];
}
return data;
}
存储与获取
ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Apple *apple = [[Apple alloc] init];
apple.name = @"JiKeXueYuan";
apple.age = @(30);
// save state
[MementoCenter saveMementoObject:apple withKey:@"Apple"];
// get state
[apple recoverFromState:[MementoCenter mementoObjectWithKey:@"Apple"]];
NSLog(@"name:%@ age:%@", apple.name, apple.age);
}
通过category优化
NSObject + MementoCenter
@implementation NSObject (MementoCenter)
- (void)saveStateWithKey:(NSString *)key {
NSParameterAssert(key);
id <MementoCenterProtocol> obj = (id <MementoCenterProtocol>)self;
if ([obj respondsToSelector:@selector(currentState)]) {
[MementoCenter saveMementoObject:obj withKey:key];
}
}
- (void)recoverFromStateWithKey:(NSString *)key {
NSParameterAssert(key);
id state = [MementoCenter mementoObjectWithKey:key];
id <MementoCenterProtocol> obj = (id <MementoCenterProtocol>)self;
if ([obj respondsToSelector:@selector(recoverFromStateWithKey:)]) {
[obj recoverFromState:state];
}
}
传递协议对象所必须的判断
id <MementoCenterProtocol> obj = (id <MementoCenterProtocol>)self;
if ([obj respondsToSelector:@selector(currentState)]) {
[MementoCenter saveMementoObject:obj withKey:key];
}
优化后的存储与获取
ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Apple *apple = [[Apple alloc] init];
apple.name = @"JiKeXueYuan";
apple.age = @(30);
[apple saveStateWithKey:@"Ben"];
[apple recoverFromStateWithKey:@"Ben"];
NSLog(@"name:%@ age:%@", apple.name, apple.age);
}
备忘录模式恢复UIView状态
使用场景:UIView有NSCoding协议,意味着可以本地存储,但没有NSCopying,意味着如果要将一个view完整的复制过来,那是一个棘手的问题。
一个对象状态的存储并不是要整个对象,也有可能是其部分的属性,由需求来定
DemoView
@interface DemoView : UIView <MementoCenterProtocol>
@end
@implementation DemoView
- (id)currentState {
return @{@"frame" : NSStringFromCGRect(self.frame)};
}
- (void)recoverFromState:(id)state {
NSDictionary *data = state;
self.frame = CGRectFromString(data[@"frame"]);
}
ViewController
- (void)viewDidLoad {
[super viewDidLoad];
DemoView *demoView = [[DemoView alloc] init];
demoView.frame = CGRectMake(100, 100, 100, 100);
[demoView saveStateWithKey:@"A"];
[demoView recoverFromStateWithKey:@"A"];
NSLog(@"%@", demoView);
}