首页 > 代码库 > iOS数据存储的几种方式

iOS数据存储的几种方式

iOS的数据存储是iOS应用开发的重要知识点:

关于这方面知识,网上有很多介绍,但对于代码层次的使用方式并未有系统全面介绍。此文章针对iOS稍熟悉的童鞋,需要对CoreData的原理有一定的了解。目前存储方式大概有以下几种:

  1. NSKeyedArchiver  适用简单数据加密
  2. NSUserDefaults  适用配置参数
  3. Write  文件操作,同NSKeyedArchiver
  4. SQLite3  操作较复杂,不建议使用。
  5. CoreData  取代SQLite3,但要遵循NSManagedObjectContext基本规则。

UT代码确保使用方式正确。请阅读以下内容:

#import <XCTest/XCTest.h>
#import <sqlite3.h>
#import "CoreDataHelper.h"

@interface StudyUITests : XCTestCase

@end

@implementation StudyUITests

- (void)setUp
{
    [super setUp];
}

- (void)tearDown
{
    [super tearDown];
}

-(void)testCoreData{
    CoreDataHelper *coreHelper = [[CoreDataHelper alloc] init];
    [coreHelper coreDataTest];
}


-(void)testSqlite3{
    sqlite3 *db;
    
    NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSString *databasePath = [documentPath stringByAppendingPathComponent:@"test.sqlite"];
    
    NSLog(@"db path: %@",databasePath);
    
    
    if(sqlite3_open([databasePath UTF8String], &db) != SQLITE_OK){
        sqlite3_close(db);
        NSLog(@"open sqlite fail!");
        NSAssert(FALSE, @"create sqlite error");
    }
    
    NSString *sqlCreateTable = @"CREATE TABLE IF NOT EXISTS ptable (ID INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, address TEXT)";
    char *error;
    if(sqlite3_exec(db, [sqlCreateTable UTF8String], NULL, NULL, &error) != SQLITE_OK){
        sqlite3_close(db);
        NSLog(@"can not create table.");
        NSAssert(FALSE, @"create table error");
    }
    
    NSString *deleteAllSql = @"delete from ptable";
    if(sqlite3_exec(db, [deleteAllSql UTF8String], NULL, NULL, &error) != SQLITE_OK){
        sqlite3_close(db);
        NSLog(@"delete values from table");
        NSAssert(FALSE, @"delete values from table");
    }
    
    NSString *sql1 = [NSString stringWithFormat:
                      @"INSERT INTO '%@' ('%@', '%@', '%@') VALUES ('%@', '%@', '%@')",
                      @"ptable", @"name", @"age", @"address", @"first name", @"23", @"pukou"];
    
    NSString *sql2 = [NSString stringWithFormat:
                      @"INSERT INTO '%@' ('%@', '%@', '%@') VALUES ('%@', '%@', '%@')",
                      @"ptable", @"name", @"age", @"address",@"second name", @"20", @"qixia"];
    
    if(sqlite3_exec(db, [sql1 UTF8String], NULL, NULL, &error) != SQLITE_OK){
        sqlite3_close(db);
        NSLog(@"can not insert sql1");
        NSAssert(FALSE, @"create insert db (sql1) error");
    }
    
    if(sqlite3_exec(db, [sql2 UTF8String], NULL, NULL, &error) != SQLITE_OK){
        sqlite3_close(db);
        NSLog(@"can not insert sql2");
        NSAssert(FALSE, @"create insert db (sql2) error");
    }
    
    
    //Read data and check result.
    
    NSString *query = @"select * from ptable";
    
    sqlite3_stmt *statement;
    
    
    if(sqlite3_prepare_v2(db, [query UTF8String], -1, &statement, nil) == SQLITE_OK){
        //start to traverse data
        
        int size = 0;
        while (sqlite3_step(statement) == SQLITE_ROW) {
            size++;
            char *name = (char*)sqlite3_column_text(statement, 1);
            int age= (int)sqlite3_column_int(statement, 2);
            char *address = (char*)sqlite3_column_text(statement, 3);
            
            NSString *nameStr = [[NSString alloc] initWithUTF8String:name];
            NSString *addressStr = [[NSString alloc] initWithUTF8String:address];
            NSLog(@"name: %@  age: %d address: %@",nameStr,age,addressStr);
        }
        NSAssert(size == 2, @"size should 2");
    }else{
        NSAssert(FALSE, @"query db error");
    }
    sqlite3_close(db);
}

-(void)testWriteToFile{
    NSString *st1 = @"first";
    NSString *st2 = @"second";
    
    NSArray *array = [NSArray arrayWithObjects:st1,st2, nil];
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSAssert(path != nil, @"path is nil");
    NSString *filename = [path stringByAppendingPathComponent:@"test.data"];
    NSAssert([array writeToFile:filename atomically:YES],@"write successfully");
    
    NSMutableArray *savearray = [NSMutableArray arrayWithContentsOfFile:filename];
    
    
    NSAssert([[savearray objectAtIndex:0] isEqualToString:st1], @"not equal to str1");
    NSAssert([[savearray objectAtIndex:1] isEqualToString:st2], @"not equal to str2");
    
}

-(void)testUserDefault{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSString *name = @"test";
    [defaults setObject:name forKey:@"name"];
    
    UIImage *image = [UIImage imageNamed:@"photo"];
    
    NSData *imageData = UIImagePNGRepresentation(image);
    [defaults setObject:imageData forKey:@"image"];
    
    //now read from data
    
    
    NSString *name1=  [defaults objectForKey:@"name"];
    NSData *imageData1 = [defaults objectForKey:@"image"];
    
    NSAssert([name1 isEqualToString:name], @"name1 is equal to test");
    NSAssert([imageData1 isEqualToData:imageData], @"image data is not equal");
    
}

-(void)testKeyedArchiver{
    NSString *save1 =@"test1";
    NSString *save2 =@"test2";
    
    
    NSArray *array = [NSArray arrayWithObjects:save1, save2, nil];
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    
    
    NSString *filename = [path stringByAppendingPathComponent:@"savedatatest"];
    NSLog(@"filename : %@",filename);
    
    //save data
    NSAssert([NSKeyedArchiver archiveRootObject:array toFile:filename],@"archive successfully.");
    
    array = [NSKeyedUnarchiver unarchiveObjectWithFile:filename];
    
    save1 = [array objectAtIndex:0];
    
    NSAssert([save1 isEqualToString:@"test1"], @"save1 must equals to test1");
    
    save2 = [array objectAtIndex:1];
    NSAssert([save2 isEqualToString:@"test2"], @"save1 must equals to test2");
   
}



@end



CoreData的使用稍微复杂一些,所以将其单独放入Helper类中。Entity model包含name,age 和 address 三个属性。可在测试工程创建,并生成Entity对象。

#import "CoreDataHelper.h"
#import <CoreData/CoreData.h>
#import "Entity.h"


@interface CoreDataHelper()

@property (strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;


-(NSPersistentStoreCoordinator *)persistentStoreCoordinator;
-(NSManagedObjectContext *)managedObjectContext;
-(NSManagedObjectModel *)managedObjectModel;



@end
@implementation CoreDataHelper



-(void)coreDataTest{
    NSError *error = nil;

    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Entity" inManagedObjectContext:self.managedObjectContext];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entityDescription];
    
    NSArray *oldResult = [[self.managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
    for (Entity *bb in oldResult) {
        [self.managedObjectContext deleteObject:bb];
    }
    NSAssert([self.managedObjectContext save:&error], @"deleting.....");
    
    
    /******insert *****/
    Entity *entity = [[Entity alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:nil];
    
    entity.name = @"test";
    entity.age = [NSNumber numberWithInt:20];
    entity.address = @"beijing";

    [self.managedObjectContext insertObject:entity];
    NSAssert([self.managedObjectContext save:&error], @"inserting.....");
    
    
    /*****query *****/
    NSSortDescriptor *sortDescription = [[NSSortDescriptor alloc] initWithKey:@"age" ascending:NO];
    NSArray *sortDescriptions = [[NSArray alloc] initWithObjects:sortDescription, nil];
    [request setSortDescriptors:sortDescriptions];
    
    NSMutableArray *array = [[self.managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
    
    for (Entity *bb in array) {
        NSLog(@"name: %@ age:%@ address:%@",bb.name,bb.age,bb.address);
    }
    NSAssert([array count] == 1, @"count size is equal to 1");
    
    
    /***** update and check****/
    NSArray *updateResult = [[self.managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
    Entity *first = [updateResult objectAtIndex:0];
    first.name = @"one";
    NSAssert([self.managedObjectContext save:&error], @"updating.....");
    
    
    updateResult = [[self.managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
    first = [updateResult objectAtIndex:0];
    NSAssert([first.name isEqualToString:@"one"], @"need to equeal one");
    
    /**** insert and check ****/
    entity = [[Entity alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:nil];
    
    entity.name = @"test2";
    entity.age = [NSNumber numberWithInt:23];
    entity.address = @"nanjing";
    [self.managedObjectContext insertObject:entity];
    NSAssert([self.managedObjectContext save:&error], @"inserting.....");
    array = [[self.managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
    for (Entity *bb in array) {
        NSLog(@"name: %@ age:%@ address:%@",bb.name,bb.age,bb.address);
    }
    NSAssert([array count] == 2, @"now size is equal to 2");
    
    
}


-(NSPersistentStoreCoordinator *)persistentStoreCoordinator{
    if(_persistentStoreCoordinator)
        return _persistentStoreCoordinator;
    
    
    NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    
    NSURL *storeURL = [NSURL fileURLWithPath:[documentPath stringByAppendingPathComponent:@"person.sqlite"]];
    
    NSError *error = nil;
    
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    
    
    if(![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]){
        NSLog(@"persistent error : %@",[error userInfo]);
    }
    return _persistentStoreCoordinator;
}


-(NSManagedObjectContext *)managedObjectContext{
    if(_managedObjectContext)
        return _managedObjectContext;
    
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    
    if(coordinator){
        _managedObjectContext = [[NSManagedObjectContext alloc] init];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return  _managedObjectContext;
}


-(NSManagedObjectModel *)managedObjectModel{
    if(_managedObjectModel)
        return _managedObjectModel;
    
    NSURL *modeUrl = [[NSBundle mainBundle] URLForResource:@"Entity" withExtension:@"momd"];
    _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modeUrl];
    return  _managedObjectModel;
}

@end