美文网首页
数据存储

数据存储

作者: CoderLNHui | 来源:发表于2017-01-12 15:12 被阅读11次

    iOS应用数据存储的常用方式

    1. Plist存储(属性列表)

    • Plist存储(Documents)
    // 1.Plist存储(生成plist文件)
    // 在Plist文件中不能保存自定义对象*+
    - (IBAction)saveBtn:(UIButton *)sender {
        // 参数:搜索的目录,搜索的范围,是否展开路径
        NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
        NSLog(@"%@",path);
    
        // 1.把数组保存到沙盒
        NSArray *dataArray = @[@"LN",@10];
        NSString *filePath = [path stringByAppendingPathComponent:@"data.plist"];
        NSLog(@"%@",filePath);
    
        // 写入沙盒路径
        [dataArray writeToFile:filePath atomically:YES];
    
        // 2.把字典保存到沙盒
        NSDictionary *dict = @{@"name":@"LN",@"age":@10};
        NSString *dictPath = [path stringByAppendingPathComponent:@"dict.plist"];
        [dict writeToFile:dictPath atomically:YES];
    }
    
    • Plist提取
    • 特点: 只能存储系统自带的数据类型, 比如NSDictory, NSArray等等. 自定义的对象无法存储
    
    // 2.Plist提取
    - (IBAction)readBtn:(UIButton *)sender {
        NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
        NSString *filePath = [path stringByAppendingPathComponent:@"data.plist"];
        NSArray *dataArray = [NSArray arrayWithContentsOfFile:filePath];
        NSLog(@"%@",dataArray);
    
        NSString *filePath1 = [path stringByAppendingPathComponent:@"dict.plist"];
        NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:filePath1];
        NSLog(@"%@",dict);
    }
    

    2. preference(偏好设置)

    • 特点: 本质就是一个plist文件; 也是只能存储系统自带的数据类型, 自定义的对象无法存储

    • NSUserDefaults: 用来保存应用程序设置和属性、用户保存的数据。用户再次打开程序或开机后这些数据仍然存在。

    • NSUserDefaults可以存储的数据类型包括:NSData、NSString、NSNumber、NSDate、NSArray、NSDictionary。如果要存储其他类型,则需要转换为前 面的类型(一般转换成NSData),才能用NSUserDefaults存储。

    • 偏好设置存储(Library/Preferences)

    
    #define LNname @"name"
    #define LNage @"age"
    
    // 1.偏好设置存储(key存取,最好定义成宏以防写错)
    // 偏好设置不能保存自定义对象*+
    - (IBAction)saveBtn:(UIButton *)sender {
        // NSUserDefaults保存也是plist文件
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        [defaults setObject:@"LN" forKey:LNname];
        [defaults setObject:@10 forKey:LNage];
        
        // 写入文件当中
        [defaults synchronize];
        NSLog(@"%@",NSHomeDirectory());
    }
    
    • 偏好设置提取
    
    // 2.偏好设置提取
    - (IBAction)readBtn:(UIButton *)sender {
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        NSString *name = [defaults objectForKey:LNname];
        NSInteger age = [defaults integerForKeyLNage];
        
        NSLog(@"%@ %ld",name,age);
    }
    

    3. NSKeyedArchiver归档(NSCoding协议)

    • 特点: 可以存储自己定义的数据类型, 但是都是一次性的全数据操作

    Person

    
    //  Person.h
    #import <Foundation/Foundation.h>
    @class Dog;
    @interface Person : NSObject<NSCoding>
    
    @property (nonatomic, strong) NSString *name;
    @property (nonatomic, assign) int age;
    @property (nonatomic, strong) Dog *dog;
    @end
    
    //  Person.m
    #import "Person.h"
    @implementation Person
    
    // 归档存储会调用(在保存对象时要告诉保存对象那些属性)
    - (void)encodeWithCoder:(NSCoder *)aCoder{
        [aCoder encodeObject:self.name forKey:@"name"];
        [aCoder encodeInt:self.age forKey:@"age"];
        [aCoder encodeObject:self.dog forKey:@"dog"];
    }
    
    // 归档提取(解析文件的时候)会调用,(告诉当前要解析文件当中哪些属性)
    - (instancetype)initWithCoder:(NSCoder *)aDecoder{
        /*
            当只有遵守了NSCoding协议时,才有[super initWithCoder]
        @interface Person : NSObject (父类NSObject没有遵守NSCoding协议,继承UIView就可以)
        */
        if (self = [super init]) {
            self.name = [aDecoder decodeObjectForKey:@"name"];
            self.age = [aDecoder decodeIntForKey:@"age"];
            self.dog = [aDecoder decodeObjectForKey:@"dog"];
        }
        return self;
    }
    
    • 归档存储(tmp,生成的文件不可以直接打开)
    
    // 归档
    // 保存自定义对象(模型类要遵守<NSCoding>协议)*+
    - (IBAction)saveBtn:(UIButton *)sender {Person *person = [[Person alloc] init];
        person.name = @"LN";
        person.age = 10;
    
        Dog *dog = [[Dog alloc] init];
        dog.name = @"xiao Hui";
        person.dog = dog;
        
        // 获取沙盒目录
        NSString *tmpPath = NSTemporaryDirectory();
        NSString *filePath = [tmpPath stringByAppendingPathComponent:@"Person.data"];
        NSLog(@"%@",NSTemporaryDirectory());
            
        // 归档(archiveRootObject会调用encodeWithCoder:)
        [NSKeyedArchiver archiveRootObject:person toFile:filePath];
    }
    
    
    • 归档提取
    
    // 2.归档提取
    - (IBAction)readBtn:(UIButton *)sender {
        // 获取沙盒目录
        NSString *tmpPath = NSTemporaryDirectory();
        NSString *filePath = [tmpPath stringByAppendingPathComponent:@"Person.data"];
        
        //归档提取 unarchiveObjectWithFile会调用initWithCoder:
        Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
        NSLog(@"%@--%@",person.name,person.dog.name);
    }
    
    • 注意点
      initWithCoderawakeFromNib
    //从xib当加载的时候 (是加载完毕时调用)
    -(void)awakeFromNib{
        NSLog(@"awakeFromNib==%@",self.btn);
        // awakeFromNib==<UIButton: 0x7ffd08c1e450; frame = (100 153; 46 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7ffd08c1af60>>
    }
    
    //当解析一个文件的时候会调用initWithCoder (一开始加载Xib就调用)
    -(instancetype)initWithCoder:(NSCoder *)aDecoder{
        if(self = [super initWithCoder:aDecoder]){
            NSLog(@"initWithCoder==%@",self.btn);
            // initWithCoder==(null)
        }
        return self;
    }
    

    4. SQLite3

    • 数据库(Database)是按照数据结构来组织、存储和管理数据的仓库

    • 数据库可以分为2大种类

      • 关系型数据库(主流):如,MySQL
      • 嵌入式/移动客户端 :如,SQLite 对象型数据库
    • 特点: 存储一些大批量的数据, 排序, 统计等操作

    什么是SQLite

    • SQLite是一款轻型的嵌入式数据库
    • 它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了
    • 它的处理速度比Mysql、PostgreSQL这两款著名的数据库都还快

    如何存储数据到数据库

    • 数据库的存储结构和excel很像,以表(table)为单位

    数据库存储数据的步骤

    • 新建数据库文件
    • 新建一张表(table)
    • 添加多个字段(column,列,属性)
    • 添加多行记录(row,每行存放多个字段对应的值)

    Navicat 是一套适用于MySQL, SQLite等多个数据库系统地图形化数据库管理、报告以及监控的工具。具有高性能的、商业智能的、强大的备份功能

    理论基础:

    • 表格组成: 行(记录)和列(属性)

    • "属性" 是用来标识这一列应该存放什么

    • "记录" 是用来存放一条数据

    • 属性类型

    • blob :二进制类型

    • integer : 整型

    • real : 浮点型

    • text :文本类型

    null : 空

    • 主键

    • 主键(Primary Key,简称PK)用来唯一地标识某一条记录

    例如t_student可以增加一个id字段作为主键,相当于人的身份证

    • 主键可以是一个字段或多个字段

      例如: 行和列

    • 主键的设计原则

      • 主键应当是对用户没有意义的
      • 永远也不要更新主键
      • 主键不应包含动态变化的数据
      • 主键应当由计算机自动生成

    SQL语言简介

    • 特点:不区分大小写(比如数据库认为user和UsEr是一样的)
    • SQL中的常用关键字(注意:数据库中不可以使用关键字来命名表、字段)

    select、insert、update、delete、from、create、where、desc、order、by、group、table、alter、view、index等等

    • SQL语句的种类
      • 数据定义语句(DDL:Data Definition Language)

      包括create和drop, Alert等操作,在数据库中创建新表或删除表(create table或 drop table)

    • 数据操作语句(DML:Data Manipulation Language)

      包括insert、delete、update等操作,上面的3种操作分别用于添加、修改、删除表中的数据

    • 数据查询语句(DQL:Data Query Language)

    可以用于查询获得表中的数据,关键字select是DQL(也是所有SQL)用得最多的操作,其他DQL常用的关键字有where,order by,group by和having

    DDL语句

    • 创表
     格式
     create table 表名 (字段名1 字段类型1, 字段名2 字段类型2, …) ;
     示例
    
     create table t_student (id integer, name text, age inetger, score real) ;
    
     
    
     经验
    
     实际上SQLite是无类型的
    
     就算声明为integer类型,还是能存储字符串文本(主键除外)
    
     
    
     建表时声明啥类型或者不声明类型都可以,也就意味着创表语句可以这么写:
    
     
    
     create table t_student(name, age);
    
     
    
     为了保持良好的编程规范、方便程序员之间的交流,编写建表语句的时候最好加上每个字段的具体类型
    
     
    
     语句优化
    
     
    
     创建表格时, 最好加个表格是否已经存在的判断, 这个防止语句多次执行时发生错误
    
     
    
     create table if not exists 表名 (字段名1 字段类型1, 字段名2 字段类型2, …) ;
    
    
    • 删表
    格式
    
     
    
     drop table 表名 ;
    
     
    
     drop table if exists 表名 ;
    
     
    
     示例
    
     
    
     drop table t_student ;
    
     
    
     语句优化
    
     
    
     删除表格时, 最好加个表格是否已经存在的判断, 这个防止语句多次执行时发生错误
    
     
    
     drop table if  exists 表名 ;
    
    • 修改表
    注意: sqlite里面只能实现Alter Table的部分功能
    
     
    
     不能删除一列, 修改一个已经存在的列名
    
     
    
     修改表名
    
     
    
     ALTER TABLE 旧表名 RENAME TO 新表名
    
     
    
     新增属性
    
     
    
     ALTER TABLE 表名 ADD COLUMN 列名 数据类型 限定符
    
    • 约束

      • 简单约束

    不能为空,not null :规定字段的值不能为null
    不能重复,unique :规定字段的值必须唯一
    默认值,default :指定字段的默认值

    示例
    `create table t_student (id integer, name text not null unique, age integer not null default 1) ;`
    
    name字段不能为null,并且唯一
    age字段不能为null,并且默认为1
    
    • 主键约束

    添加主键约束的原因?
    如果t_student表中就name和age两个字段,而且有些记录的name和age字段的值都一样时,那么就没法区分这些数据,造成数据库的记录不唯一,这样就不方便管理数据,良好的数据库编程规范应该要保证每条记录的唯一性,为此,增加了主键约束,也就是说,每张表都必须有一个主键,用来标识记录的唯一性
    - 主键的声明?

    在创表的时候用primary key声明一个主键

    create table t_student (id integer primary key, name text, age integer) ;

    integer类型的id作为t_student表的主键
    - 主键字段

    只要声明为primary key,就说明是一个主键字段

    主键字段默认就包含了not null 和 unique 两个约束

    如果想要让主键自动增长(必须是integer类型),应该增加autoincrement

    create table t_student (id integer primary key autoincrement, name text, age integer) ;

    DML语句

    • 插入数据(insert)
     格式
    
     
    
     insert into 表名 (字段1, 字段2, …) values (字段1的值, 字段2的值, …) ;
    
     
    
     示例
    
     
    
     insert into t_student (name, age) values (‘sz’, 10) ;
    
     
    
     注意
    
     
    
     数据库中的字符串内容应该用单引号 ’ 括住
    
    • 更新数据(update)
    格式
    
     
    
     update 表名 set 字段1 = 字段1的值, 字段2 = 字段2的值, … ;
    
     
    
     示例
    
     
    
     update t_student set name = ‘wex’, age = 20 ;
    
     
    
     注意
    
     
    
     上面的示例会将t_student表中所有记录的name都改为wex,age都改为20
    
    • 删除数据(delete)
    格式
    
     
    
     delete from 表名 ;
    
     
    
     示例
    
     
    
     delete from t_student ;
    
     
    
     注意
    
     
    
     上面的示例会将t_student表中所有记录都删掉
    
    
    • 条件语句
    作用
    
     
    
     如果只想更新或者删除某些固定的记录,那就必须在DML语句后加上一些条件
    
     
    
     条件语句的常见格式
    
     
    
     where 字段 = 某个值 ;   // 不能用两个 =
    
     
    
     where 字段 is 某个值 ;   // is 相当于 =
    
     
    
     where 字段 != 某个值 ;
    
     
    
     where 字段 is not 某个值 ;   // is not 相当于 !=
    
     
    
     where 字段 > 某个值 ;
    
     
    
     where 字段1 = 某个值 and 字段2 > 某个值 ;  // and相当于C语言中的 &&
    
     
    
     where 字段1 = 某个值 or 字段2 = 某个值 ;  //  or 相当于C语言中的 ||
    
    • 条件语句练习

      示例

    将t_student表中年龄大于10 并且 姓名不等于wex的记录,年龄都改为 5

    删除t_student表中年龄小于等于10 或者 年龄大于30的记录

    猜猜下面语句的作用

    update t_student set score = age where name = ‘wex’ ;

    DQL

    格式
    
     
    
     select 字段1, 字段2, … from 表名 ;
    
     
    
     select * from 表名;   //  查询所有的字段
    
     
    
     示例
    
     
    
     select name, age from t_student ;
    
     
    
     select * from t_student ;
    
     
    
     select * from t_student where age > 10 ;  //  条件查询
    
    

    查询相关语句

    统计
    
     
    
     count(X)
    
     
    
     select count(*) from t_student
    
     
    
     select count(age) from t_student
    
     
    
     avg(X)
    
     
    
     计算某个字段的平均值
    
     
    
     sum(X)
    
     
    
     计算某个字段的总和
    
     
    
     max(X)
    
     
    
     计算某个字段的最大值
    
     
    
     min(X)
    
     
    
     计算某个字段的最小值
    
     
    
     排序
    
     
    
     查询出来的结果可以用order by进行排序
    
     
    
     select 字段1, 字段2 from 表名 order by 字段 ;
    
     
    
     select * from t_student order by age ;
    
     
    
     默认是按照升序排序(由小到大),也可以变为降序(由大到小)
    
     
    
     select * from t_student order by age desc ;  //降序
    
     
    
     select * from t_student order by age asc ;   // 升序(默认)
    
     
    
     也可以用多个字段进行排序
    
     
    
     select * from t_student order by age asc, height desc ;
    
     
    
     先按照年龄排序(升序),年龄相等就按照身高排序(降序)
    
     
    
     limit分页
    
     
    
     使用limit可以精确地控制查询结果的数量,比如每次只查询10条数据
    
     
    
     格式
    
     
    
     select * from 表名 limit 数值1, 数值2 ;
    
     
    
     示例
    
     
    
     select * from t_student limit 4, 8 ;
    
     
    
     可以理解为:跳过最前面4条语句,然后取8条记录
    
     
    
     分页
    
     
    
     limit常用来做分页查询,比如每页固定显示5条数据,那么应该这样取数据
    
     
    
     第1页:limit 0, 5
    
     
    
     第2页:limit 5, 5
    
     
    
     第3页:limit 10, 5
    
     
    
     第n页:limit 5*(n-1), 5
    
     
    
     特殊案例
    
     
    
     select * from t_student limit 7 ;
    
     
    
     相当于select * from t_student limit 0, 7 ;
    
     
    
     表示取最前面的7条记录
    

    多表查询

    
    select 字段1, 字段2, … from 表名1, 表名2 ;
    
     
    
     别名
    
     
    
     select
    
     
    
     别名1.字段1 as 字段别名1,
    
     
    
     别名2.字段2 as 字段别名2,
    
     
    
     …
    
     
    
     from
    
     
    
     表名1 as 别名1,
    
     
    
     表名2 as 别名2 ;
    
     
    
     可以给表或者字段单独起别名
    
     
    
     as 可以省略
    
     
    
     表连接查询
    
     
    
     select 字段1, 字段2, … from 表名1, 表名2  where 表名1.id = 表名2.id;
    
     
    
     外键
    
     
    
     如果表A的主关键字是表B中的字段,则该字段称为表B的外键
    
     
    
     保持数据一致性,完整性,主要目的是控制存储在外键表中的数据。 使两张表形成关联,外键只能引用外表中的列的值或使用空值。
    
     
    
    12-(掌握)代码实现SQLite-DDL
    
     
    
     1. 创建一个Swift项目
    
     
    
     2. 导入系统框架sqlite3.tbd(sqlite3.dylib)
    
     
    
     3. 建立桥接文件, 导入头文件sqlite3.h
    
     
    
     1. 新建一个.h 头文件
    
     
    
     2. 设置为桥接文件
    
    

    代码实现

    
    1. 打开数据库
    
     
    
     2. 使用打开的数据库, 执行DDL语句, 创建一个数据库表
    
     
    
     3.  使用打开的数据库, 执行DDL语句, 创建一个数据库表
    
     
    
     3. 将数据库操作封装成一个工具类
    
     
    
    13-(掌握)代码实现DML语句-Insert
    
     
    
     1. 创建一个Student类
    
     
    
     属性
    
     
    
     name
    
     
    
     age
    
     
    
     构造方法
    
     
    
     init(name: String, age: Int)
    
     
    
     2. 创建数据库操作方法
    
     
    
     数据库中, 对Student对象的操作封装
    
     
    
     insertStudent()
    
     
    
    14-(了解)代码实现DML语句-Insert绑定参数
    
     
    
     准备语句(prepared statement)对象
    
     
    
     准备语句(prepared statement)对象一个代表一个简单SQL语句对象的实例,这个对象通常被称为“准备语句”或者“编译好的SQL语句”或者就直接称为“语句”。
    
     
    
     操作历程
    
     
    
     1. 使用sqlite3_prepare_v2或相关的函数创建这个对象
    
     
    
     如果执行成功,则返回SQLITE_OK,否则返回一个错误码
    
     
    
     2. 使用sqlite3_bind_*()给宿主参数(host parameters)绑定值
    
     
    
     sqlite3_bind_text
    
     
    
     参数1:
    
     
    
     准备语句
    
     
    
     参数2:
    
     
    
     绑定的参数索引  (从1开始)
    
     
    
     参数3:
    
     
    
     绑定的参数内容
    
     
    
     参数4:
    
     
    
     绑定的参数长度  (-1代表自动计算长度)
    
     
    
     参数5:
    
     
    
     参数的处理方式
    
     
    
     SQLITE_TRANSIENT 会对字符串做一个 copy,SQLite 选择合适的机会释放
    
     
    
     SQLITE_STATIC / nil  把它当做全局静态变量, 不会字符串做任何处理,如果字符串被释放,保存到数据库的内容可能不正确!
    
     
    
     注意: swift中没有宏的概念
    
     
    
     // 替换 sqlite3.h 中的宏
    
     
    
     private let SQLITE_TRANSIENT = unsafeBitCast(-1, sqlite3_destructor_type.self)
    
     
    
     3.  通过调用sqlite3_step() 一次或多次来执行这个sql
    
     
    
     对于DML语句, 如果执行成功, 返回SQLITE_DONE
    
     
    
     对于DQL语句, 通过多次执行获取结果集, 继续执行的条件是返回值 SQLITE_ROW
    
     
    
     4.  使用sqlite3_reset()重置这个语句,然后回到第2步,这个过程做0次或多次
    
     
    
     5. 使用sqlite3_finalize()销毁这个对象, 防止内存泄露
    
    

    DML语句-Insert插入数据优化

    只要在执行多个SQL语句之前, 手动开启事务, 在执行完毕之后, 手动提交事务, 这样 再调用SQL方法执行语句时, 就不会再自动开启和提交事务

    事务

    5. Core Data

    • 特点: 对SQLite3的一层面向对象的包装, 本质还是要转换成为对应的SQL语句去执行

    钥匙串

    • APP之间数据共享
    • 系统级别的加密, 安全性高
    • 当APP 被删除时, 存储的数据依然存在

    相关文章

      网友评论

          本文标题:数据存储

          本文链接:https://www.haomeiwen.com/subject/szwdbttx.html