iOS持久化
在iOS开发中我们经常会遇到数据的存储问题,在iOS中我们常用的数据存储方式有 plist存储,偏好设置,归档以及数据库存储。
在学习持久化之前我们先了解一下数据常用的存储路径
源文件路径
NSString *path = [[NSBundle mainBundle] bundlePath];
Documents
最常用的目录,iTunes同步该应用时会同步此文件夹中的内容,适合存储重要数据。
NSString *path1 = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
Library/Caches:
iTunes不会同步此文件夹,适合存储体积大,不需要备份的非重要数据。通常保存应用的设置信息。
NSString *path2 = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
tmp:
iTunes不会同步此文件夹,系统可能在应用没运行时就删除该目录下的文件,所以此目录适合保存应用中的一些临时文件,用完就删除。
NSString *path3 = NSTemporaryDirectory();
好了,下面进入我们的正题,数据持久化
-plist存储
该存储方式只能对基本类型的数据进行持久化如:
NSArray;
NSMutableArray;
NSDictionary;
NSMutableDictionary;
NSData;
NSMutableData;
NSString;
NSMutableString;
NSNumber;
NSDate;
存储时使用writeToFile: atomically:方法。 其中atomically表示是否需要先写入一个辅助文件,再把辅助文件拷贝到目标文件地址。这是更安全的写入文件方法,一般都写YES。
读取时使用arrayWithContentsOfFile:方法。
//1.获得文件路径
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *fileName = [path stringByAppendingPathComponent:@"123.plist"];
//2.存储
NSArray *array = @[@"123", @"456", @"789"];
[array writeToFile:fileName atomically:YES];
// 3.读取
NSArray *result = [NSArray arrayWithContentsOfFile:fileName];
NSLog(@"%@", result);
-偏好设置
偏好设置是专门用来保存应用程序的配置信息的,一般不要在偏好设置中保存其他数据。
如果没有调用synchronize方法,系统会根据I/O情况不定时刻地保存到文件中。所以如果需要立即写入文件的就必须调用synchronize方法。
偏好设置会将所有数据保存到同一个文件中。即preference目录下的一个以此应用包名来命名的plist文件。
//1.获得NSUserDefaults文件
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
//2.向文件中写入内容
[userDefaults setObject:@"AAA" forKey:@"a"];
[userDefaults setBool:YES forKey:@"sex"];
[userDefaults setInteger:21 forKey:@"age"];
//2.1立即同步
[userDefaults synchronize];
//3.读取文件
NSString *name = [userDefaults objectForKey:@"a"];
BOOL sex = [userDefaults boolForKey:@"sex"];
NSInteger age = [userDefaults integerForKey:@"age"];
NSLog(@"%@, %d, %ld", name, sex, age);
-归档
如果需要归档的类是某个自定义类的子类时,就需要在归档和解档之前先实现父类的归档和解档方法。
即 [super encodeWithCoder:aCoder]
和 [super initWithCoder:aDecoder]
方法;
必须遵循并实现NSCoding协议
保存文件的扩展名可以任意指定
继承时必须先调用父类的归档解档方法
-实现归档和解档方法
person.h
//
// person.h
// OC知识点整理
//
// Created by li on 17/2/27.
// Copyright © 2017年 李文强. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface person : NSObject
@property (strong, nonatomic)NSString*avatar;
@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic) NSInteger age;
@end
person.m
//
// person.m
// OC知识点整理
//
// Created by li on 17/2/27.
// Copyright © 2017年 李文强. All rights reserved.
//
#import "person.h"
@interface person()<NSCoding> //2.设置属性
@end
@implementation person
//解档
- (id)initWithCoder:(NSCoder *)aDecoder {
if ([super init]) {
self.avatar = [aDecoder decodeObjectForKey:@"avatar"];
self.name = [aDecoder decodeObjectForKey:@"name"];
self.age = [aDecoder decodeIntegerForKey:@"age"];
}
return self;
}
//归档
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.avatar forKey:@"avatar"];
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeInteger:self.age forKey:@"age"];
}
@end
-实现持久化
//
// mainViewController.m
// OC知识点整理
//
// Created by li on 17/2/27.
// Copyright © 2017年 李文强. All rights reserved.
//
#import "mainViewController.h"
#import "person.h"
@interface mainViewController ()
@end
@implementation mainViewController
-(void)NSKeyedArchiver{
//存
NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.data"];
person *per=[[person alloc]init];
per.avatar=@"123";
per.name=@"456";
per.age=16;
[NSKeyedArchiver archiveRootObject:per toFile:file];
//取
person*per2=[NSKeyedUnarchiver unarchiveObjectWithFile:file];
}
@end
-数据库
使用数据库必须先要添加libsqlite3.tbd库
//
// SQLite.m
// OC知识点整理
//
// Created by li on 17/2/27.
// Copyright © 2017年 李文强. All rights reserved.
//
#import "SQLite.h"
#import <SQLite3.h>
@interface SQLite()
@end
@implementation SQLite
static sqlite3*_sqlite3;
/**
打开数据库并创建一个表
*/
- (void)openDatabase {
//1.设置文件名
NSString *filename = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.db"];
//2.打开数据库文件,如果没有会自动创建一个文件
NSInteger result = sqlite3_open(filename.UTF8String, &_sqlite3);
if (result == SQLITE_OK) {
NSLog(@"打开数据库成功!");
//3.创建一个数据库表
char *errmsg = NULL;
sqlite3_exec(_sqlite3, "CREATE TABLE IF NOT EXISTS t_person(id integer primary key autoincrement, name text, age integer)", NULL, NULL, &errmsg);
if (errmsg) {
NSLog(@"错误:%s", errmsg);
} else {
NSLog(@"创表成功!");
}
} else {
NSLog(@"打开数据库失败!");
}
}
/**
* 往表中插入数据
*/
- (void)insertData {
NSString *nameStr;
NSInteger age;
nameStr = [NSString stringWithFormat:@"Bourne-%d", arc4random_uniform(10000)];
age = arc4random_uniform(80) + 20;
NSString *sql = [NSString stringWithFormat:@"INSERT INTO t_person (name, age) VALUES('%@', '%ld')", nameStr, age];
char *errmsg = NULL;
sqlite3_exec(_sqlite3, sql.UTF8String, NULL, NULL, &errmsg);
if (errmsg) {
NSLog(@"错误:%s", errmsg);
}
NSLog(@"插入完毕!");
}
/**
* 从表中读取数据到数组中
*/
- (void)readData {
char *sql = "select name, age from t_person;";
sqlite3_stmt *stmt;
NSInteger result = sqlite3_prepare_v2(_sqlite3, sql, -1, &stmt, NULL);
if (result == SQLITE_OK) {
while (sqlite3_step(stmt) == SQLITE_ROW) {
char *name = (char *)sqlite3_column_text(stmt, 0);
NSInteger age = sqlite3_column_int(stmt, 1);
NSLog(@"%s %ld",name,age);
}
}
sqlite3_finalize(stmt);
}
@end