Cowboy Tech

iOS设计模式-备忘录

备忘录模式

  1. 备忘录模式,什么都可以存!
  2. 先设计抽象接口,再去考虑实现细节

设计存储中心

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);
}