剖析Objective-C持久化教程是本文要介绍的内容,很详细的讲解了Objective-C持久化的问题,不多说,我们来看内容。
当前需求
在做登录模块时,需要做登录的历史记录,存储本机所有登录的用户的用户名密码,以及登录策略如是否记住密码,是否自动登录等。具体实现之前,我认为这个需求看样子并不需要SQLite,因为登录用户不可能太多,而且存储的字段也就四个而已,估计用NSUserDefaults存一下数组就结了。
初遇困难
令我沮丧的是,这么一个明确的需求竟然一时半会都没有完成,用户登陆信息明明很简单的
Objective-c代码
- @interface LoginUserInfo : NSObject
- {
- NSString *username_;
- NSString *password_;
- BOOL remember_;
- BOOL autoLogin_;
- }
- @property (nonatomic, copy) NSString *username;
- @property (nonatomic, copy) NSString *password;
- @property (nonatomic, assign) BOOL remember;
- @property (nonatomic, assign) BOOL autoLogin;
- @end
- @protocol LoginHistoryDelegate;
- @interface LoginUserInfo : NSObject
- {
- NSString *username_;
- NSString *password_;
- BOOL remember_;
- BOOL autoLogin_;
- }
- @property (nonatomic, copy) NSString *username;
- @property (nonatomic, copy) NSString *password;
- @property (nonatomic, assign) BOOL remember;
- @property (nonatomic, assign) BOOL autoLogin;
- @end
- @protocol LoginHistoryDelegate;
存取的时候也很简单
Objective-c代码
- // 增加一个用户要看是否是新用户,如果是新的就增加,否则要修改
- - (void)addUser:(LoginUserInfo *)info
- {
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- NSArray *list = [self getUserList];
- NSArray *newList = nil;
- if (list == nil)
- {
- newList = [NSArray arrayWithObject:info];
- }
- else
- {
- NSMutableArray *mutList = [[NSMutableArray alloc] initWithCapacity:[list count]+1];
- [mutList addObject:info];
- for (LoginUserInfo *user in list)
- {
- if (![[info username] isEqualToString:[user username]])
- {
- [mutList addObject:user];
- }
- }
- newList = [mutList mutableCopy];
- }
- [defaults setObject:newList forKey:kUserHistoryKey];
- [defaults synchronize];
- [newList release];
- }
- - (NSArray *)getUserList
- {
- NSArray *objectArray = [[NSUserDefaults standardUserDefaults] objectForKey:kUserHistoryKey];
- return objectArray;
- }
- // 增加一个用户要看是否是新用户,如果是新的就增加,否则要修改
- - (void)addUser:(LoginUserInfo *)info
- {
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- NSArray *list = [self getUserList];
- NSArray *newList = nil;
- if (list == nil)
- {
- newList = [NSArray arrayWithObject:info];
- }
- else
- {
- NSMutableArray *mutList = [[NSMutableArray alloc] initWithCapacity:[list count]+1];
- [mutList addObject:info];
- for (LoginUserInfo *user in list)
- {
- if (![[info username] isEqualToString:[user username]])
- {
- [mutList addObject:user];
- }
- }
- newList = [mutList mutableCopy];
- }
- [defaults setObject:newList forKey:kUserHistoryKey];
- [defaults synchronize];
- [newList release];
- }
- - (NSArray *)getUserList
- {
- NSArray *objectArray = [[NSUserDefaults standardUserDefaults] objectForKey:kUserHistoryKey];
- return objectArray;
- }
但这样无论我怎么存储用户列表,在getUserList的时候获得的始终是nil。
各种尝试
难道是NSUserdefaults有问题么?我试了试在同个方法里改为存储普通的int,bool,甚至NSString都没问题,难道是因为没有存储数组么
Objective-c代码
- NSArray *arr = [NSArray arrayWithObjects:@"xixi", @"haha", nil];
- [[NSUserDefaults standardUserDefaults] setObject:arr forKey:@"Array"];
- [[NSUserDefaults standardUserDefaults] synchronize];
- NSArray *arr2 = [[NSUserDefaults standardUserDefaults] objectForKey:@"Array"];
- NSString *s1 = [arr2 objectAtIndex:0];
- NSLog(@"%@", s1);
- NSArray *arr = [NSArray arrayWithObjects:@"xixi", @"haha", nil];
- [[NSUserDefaults standardUserDefaults] setObject:arr forKey:@"Array"];
- [[NSUserDefaults standardUserDefaults] synchronize];
- NSArray *arr2 = [[NSUserDefaults standardUserDefaults] objectForKey:@"Array"];
- NSString *s1 = [arr2 objectAtIndex:0];
- NSLog(@"%@", s1);
但此时仍然可以很顺利的显示出s1为xixi 没办法只好上网找资料了,这时注意到我存储的是自定义的结构,而和java的序列化类似,在序列化自定义类型的时候,必须要满足可序列化的一系列条件,甚至包括序列化的规则,就Objective-C而言,必须要实现NSCoding协议
Objective-c代码
- - (void)encodeWithCoder:(NSCoder *)coder;
- {
- [coder encodeObject:username_ forKey:@"username"];
- [coder encodeObject:password_ forKey:@"password"];
- [coder encodeBool:remember_ forKey:@"remember"];
- [coder encodeBool:autoLogin_ forKey:@"autologin"];
- }
- - (id)initWithCoder:(NSCoder *)coder;
- {
- self = [[LoginUserInfo alloc] init];
- if (self != nil)
- {
- self.username = [coder decodeObjectForKey:@"username"];
- self.password = [coder decodeObjectForKey:@"password"];
- self.remember = [coder decodeBoolForKey:@"remember"];
- self.autoLogin = [coder decodeBoolForKey:@"autologin"];
- }
- return self;
- }
- - (void)encodeWithCoder:(NSCoder *)coder;
- {
- [coder encodeObject:username_ forKey:@"username"];
- [coder encodeObject:password_ forKey:@"password"];
- [coder encodeBool:remember_ forKey:@"remember"];
- [coder encodeBool:autoLogin_ forKey:@"autologin"];
- }
- - (id)initWithCoder:(NSCoder *)coder;
- {
- self = [[LoginUserInfo alloc] init];
- if (self != nil)
- {
- self.username = [coder decodeObjectForKey:@"username"];
- self.password = [coder decodeObjectForKey:@"password"];
- self.remember = [coder decodeBoolForKey:@"remember"];
- self.autoLogin = [coder decodeBoolForKey:@"autologin"];
- }
- return self;
- }
然后在存取的时候再加上序列化以及反序列化的代码
Objective-c代码
- - (NSArray *)getUserList
- {
- NSArray *objectArray = nil;
- NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:kUserHistoryKey];
- if (data != nil)
- {
- NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];
- if (oldSavedArray != nil)
- objectArray = [[NSArray alloc] initWithArray:oldSavedArray];
- // else
- // objectArray = [[NSMutableArray alloc] init];
- }
- return objectArray;
- }
- // 增加一个用户要看是否是新用户,如果是新的就增加,否则要修改
- - (void)addUser:(LoginUserInfo *)info
- {
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- NSArray *list = [self getUserList];
- NSArray *newList = nil;
- if (list == nil)
- {
- newList = [NSArray arrayWithObject:info];
- }
- else
- {
- NSMutableArray *mutList = [[NSMutableArray alloc] initWithCapacity:[list count]+1];
- [mutList addObject:info];
- for (LoginUserInfo *user in list)
- {
- if (![[info username] isEqualToString:[user username]])
- {
- [mutList addObject:user];
- }
- }
- newList = [mutList mutableCopy];
- }
- [defaults setObject:[NSKeyedArchiver archivedDataWithRootObject:
- newList] forKey:kUserHistoryKey];
- [defaults synchronize];
- [newList release];
- }
- - (NSArray *)getUserList
- {
- NSArray *objectArray = nil;
- NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:kUserHistoryKey];
- if (data != nil)
- {
- NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];
- if (oldSavedArray != nil)
- objectArray = [[NSArray alloc] initWithArray:oldSavedArray];
- // else
- // objectArray = [[NSMutableArray alloc] init];
- }
- return objectArray;
- }
- // 增加一个用户要看是否是新用户,如果是新的就增加,否则要修改
- - (void)addUser:(LoginUserInfo *)info
- {
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- NSArray *list = [self getUserList];
- NSArray *newList = nil;
- if (list == nil)
- {
- newList = [NSArray arrayWithObject:info];
- }
- else
- {
- NSMutableArray *mutList = [[NSMutableArray alloc] initWithCapacity:[list count]+1];
- [mutList addObject:info];
- for (LoginUserInfo *user in list)
- {
- if (![[info username] isEqualToString:[user username]])
- {
- [mutList addObject:user];
- }
- }
- newList = [mutList mutableCopy];
- }
- [defaults setObject:[NSKeyedArchiver archivedDataWithRootObject:
- newList] forKey:kUserHistoryKey];
- [defaults synchronize];
- [newList release];
- }
这样,总算可以持久化自定义结构了
和其他类似的语言一样,基础的序列化是个说大不大,说小不小的步骤,如果用纯c的话,就可以要完全自己去存储每个字节再读出每个字节然后解释出来,而现代语言基本上都做好了常见类型的持久化,包括更复杂的内置结构。
但即便如此,编译器也绝无可能理解用户自定义的结构,就像java里的 transient标注,还有持久化中内嵌持久化结构,持久化时的变量先后依赖关系等,持久化在网络中的传输等等等等,这也远远超过了本文的范畴 objective-c的困难支持可能要加上一个内存的释放方法不一等,确实很难便利的持久化。
小结:剖析Objective-C持久化教程的内容介绍完了,希望本文对你有所帮助!