[ios] 数据持久化(加密等)

从数据保存的方式上讲可以分为三大部分:属性列表、对象归档、嵌入式数据库(SQLite3)、CoreData等

这里主要解释 属性列表,对象归档

1.属性列表

首先要知道获取应用程序中能保存数据的路径, http://www.cnblogs.com/jinjiantong/archive/2013/02/23/2923717.html 这里提过

1)一种简单的方法是,获取目录路径后直接写下去

-(IBAction) save {
    
    NSArray * myPaths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
    NSString * myDocPath = [myPaths objectAtIndex:0];
    NSString *filename = [myDocPath
                          stringByAppendingPathComponent:@"properties.plist"];
    
    NSMutableArray *data = [[NSMutableArray alloc]init];
    [data addObject:studentId.text];
    [data addObject:studentName.text];
    [data addObject:studentClass.text];
    [data writeToFile:filename atomically:YES];

    [data release];
    
}

读取

    NSArray * myPaths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
    NSString * myDocPath = [myPaths objectAtIndex:0];
    NSString *filename = [myDocPath
                          stringByAppendingPathComponent:@"properties.plist"];
    
    if ([[NSFileManager defaultManager] fileExistsAtPath:filename]) {
        NSArray *data = [[NSArray alloc] initWithContentsOfFile:filename];
        studentId.text = [data objectAtIndex:0];
        studentName.text = [data objectAtIndex:1];
        studentClass.text = [data objectAtIndex:2];    
        [data release];
    }
}

2)用NSUserdefault

用NSUserdefault存储的数据在ios应用程序目录中/Library/Prefereces,里面有个plist文件,存储的就是你的userDefaults

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  [defaults setObject:@"mytest" forKey:@"mytest"];
  [defaults synchronize];  //同步化,更新你的数据 (我理解为把内存中的数据写入到文件)
  NSString *testStr = [defaults objectForKey:@"myTest"];
  NSLog(@"testStr is: %@",testStr);

3)keychain 的使用(加密)

来至:http://blog.csdn.net/weiqubo/article/details/7691278

需要导入Security.framework 

[cpp] view plaincopy
 
  1. @implementation WQKeyChain  
  2. + (NSMutableDictionary *)getKeychainQuery:(NSString *)service {  
  3. return [NSMutableDictionary dictionaryWithObjectsAndKeys:  
  4.         (__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass,  
  5.         service, (__bridge_transfer id)kSecAttrService,  
  6.         service, (__bridge_transfer id)kSecAttrAccount,  
  7.         (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,(__bridge_transfer id)kSecAttrAccessible,  
  8.         nil];  
  9. }  
  10.   
  11. + (void)save:(NSString *)service data:(id)data {  
  12.     //Get search dictionary  
  13.     NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];  
  14.     //Delete old item before add new item  
  15.     SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);  
  16.     //Add new object to search dictionary(Attention:the data format)  
  17.     [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData];  
  18.     //Add item to keychain with the search dictionary  
  19.     SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL);  
  20. }  
  21.   
  22. + (id)load:(NSString *)service {  
  23.     id ret = nil;  
  24.     NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];  
  25.     //Configure the search setting  
  26.     [keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge_transfer id)kSecReturnData];  
  27.     [keychainQuery setObject:(__bridge_transfer id)kSecMatchLimitOne forKey:(__bridge_transfer id)kSecMatchLimit];  
  28.     CFDataRef keyData = NULL;  
  29.     if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {  
  30.         @try {  
  31.             ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)keyData];  
  32.         } @catch (NSException *e) {  
  33.             NSLog(@"Unarchive of %@ failed: %@", service, e);  
  34.         } @finally {  
  35.         }  
  36.     }  
  37.     return ret;  
  38. }  
  39.   
  40. + (void)delete:(NSString *)service {  
  41.     NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];  
  42.     SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);  
  43. }  
  44. @end  
  45. 使用
  46. static NSString * const KEY_IN_KEYCHAIN = @"com.wuqian.app.allinfo";  
  47. static NSString * const KEY_PASSWORD = @"com.wuqian.app.password";  
  48.   
  49. +(void)savePassWord:(NSString *)password  
  50. {  
  51.     NSMutableDictionary *usernamepasswordKVPairs = [NSMutableDictionary dictionary];  
  52.     [usernamepasswordKVPairs setObject:password forKey:KEY_PASSWORD];  
  53.     [WQKeyChain save:KEY_IN_KEYCHAIN data:usernamepasswordKVPairs];  
  54. }  
  55.   
  56. +(id)readPassWord  
  57. {  
  58.     NSMutableDictionary *usernamepasswordKVPair = (NSMutableDictionary *)[WQKeyChain load:KEY_IN_KEYCHAIN];  
  59.     return [usernamepasswordKVPair objectForKey:KEY_PASSWORD];  
  60. }  
  61.   
  62. +(void)deletePassWord  
  63. {  
  64.     [WQKeyChain delete:KEY_IN_KEYCHAIN]; 

2.对象归档

归档”是值另一种形式的序列化,对模型对象进 行归档的技术可以轻松将复杂的对象写入文件, 然后再从中读取它们.

  首先看一下简单字符串的归档

  保存

 
    NSArray * paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
    
    NSString * myDocumentPath=[paths objectAtIndex:0];
    
    NSString * filename=[myDocumentPath stringByAppendingPathComponent:@"myDefault.txt"];
    NSMutableData *data=[NSMutableData data];
    NSKeyedArchiver * keyarchive=[[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
    if (![self.name isEqualToString:@""] &&![self.number isEqualToString:@""]) {
        
        [keyarchive encodeObject:self.name forKey:@"name"];
        [keyarchive encodeObject:self.number forKey:@"number"];
        [keyarchive finishEncoding];
        [data writeToFile:filename atomically:YES];
        [keyarchive release];
        
    }

   读取

 NSArray * paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
    
    NSString * myDocumentPath=[paths objectAtIndex:0];
    
    NSString * filename=[myDocumentPath stringByAppendingPathComponent:@"myDefault.txt"];
    NSMutableData *data=[NSMutableData data];
    data=[NSData dataWithContentsOfFile:filename];
    if (data.length>0) {
        NSKeyedUnarchiver *keyarchive=[[NSKeyedUnarchiver alloc] initForReadingWithData:data];
        self.shoujianren.text=(NSString *)[keyarchive decodeObjectForKey:@"name"];
        self.name=(NSString *)[keyarchive decodeObjectForKey:@"name"];
        self.number=(NSString *)[keyarchive decodeObjectForKey:@"number"];
        [keyarchive finishDecoding];
        [keyarchive release];
    }

如果这里保存的是一个对象,为了保证对象的独立性不能直接保存,要复制一个保存进去。这时候要用到

两个协议 NSCopying NSCoding

把一个学生的的信息保存到文件里

1.首先要有一类,实现以上两个协议

#import <Foundation/Foundation.h>

@interface Student : NSObject<NSCoding,NSCopying>
{
    NSString *stunumber;
    NSString *stuname;
    NSString *stumyclass;

}
@property (nonatomic,copy)NSString *stunumber;
@property (nonatomic,copy)NSString *stuname;
@property (nonatomic,copy)NSString *stumyclass;

@end

重写协议里的方法

#import "Student.h"

@implementation Student
@synthesize stuname;
@synthesize stunumber;
@synthesize stumyclass;

- (void)encodeWithCoder:(NSCoder *)aCoder{
    [aCoder encodeObject:self.stumyclass forKey:@"stumyclass"];
    [aCoder encodeObject:self.stuname forKey:@"stuname"];
    [aCoder encodeObject:self.stunumber forKey:@"stunumber"];
 

}
- (id)initWithCoder:(NSCoder *)aDecoder{
    self.stumyclass=[aDecoder decodeObjectForKey:@"stumyclass"];
    self.stuname=[aDecoder decodeObjectForKey:@"stuname"];
    self.stunumber=[aDecoder decodeObjectForKey:@"stunumber"];
    return  self;

}
- (id)copyWithZone:(NSZone *)zone{
    Student * copy=[[[self class] allocWithZone:zone] init];
    copy.stuname=[self.stuname copyWithZone:zone];
    copy.stumyclass=[self.stumyclass copyWithZone:zone];
    copy.stunumber=[self.stunumber copyWithZone: zone];
    return  copy;


}
@end

开始调用

- (IBAction)savewithencdoing:(id)sender {
    

    NSString *mydocumentPath=[[NSBundle mainBundle] bundlePath];
    NSString  * mydocument=[mydocumentPath stringByAppendingPathComponent:@"student.archive"];
    NSMutableData * data=[NSMutableData  data];
    //文件缓冲
    NSKeyedArchiver *keyarchive=[[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
    Student *stu=[[Student alloc] init];
    stu.stumyclass=self.myClass.text;
    stu.stuname=self.myName.text;
    stu.stunumber=self.myNumber.text;
    Student *mystu=[stu copy];   //这时候会调用协议里的copyWithZone:(NSZone *)zone 方法
    [keyarchive encodeObject:mystu forKey:@"mystu"];//这时候会调用encodeWithCoder:(NSCoder *)aCoder
    [keyarchive finishEncoding];
    [data writeToFile:mydocument atomically:YES];
    [stu release];
    [keyarchive release];
 
    
}

读取

- (IBAction)loadingwithencoding:(id)sender {
 
//    NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
//    NSString *mydocumentPath=[paths objectAtIndex:0];
    //NSString *mydocumentPath=NSTemporaryDirectory();
    NSString *mydocumentPath=[[NSBundle mainBundle] bundlePath];
    NSString  * mydocument=[mydocumentPath stringByAppendingPathComponent:@"student.archive"];
    NSMutableData * data=[NSMutableData  data];
    data=[NSData dataWithContentsOfFile:mydocument];
    if(data.length>0){
        NSKeyedUnarchiver *keyarchive=[[NSKeyedUnarchiver alloc] initForReadingWithData:data];
        Student * stu=[[[Student alloc] init] autorelease];
        stu=(Student*)[keyarchive decodeObjectForKey:@"mystu"];
        self.myNumber.text=stu.stunumber;
        self.myName.text=stu.stuname;
        self.myClass.text=stu.stumyclass;
        [keyarchive finishDecoding];
        [keyarchive release];
        //[stu release];
        
        
    }
}

原文地址:https://www.cnblogs.com/jinjiantong/p/2973030.html