zoukankan      html  css  js  c++  java
  • ios 常用的持久化数据存储方式

    1.plist文件存储

     每个iOS应用都有自己的应用沙盒(应用沙盒就是文件系统目录),与其他文件系统隔离。应用必须待在自己的沙盒里,其他应用不能访问该沙盒

    应用沙盒的文件系统目录,如下图所示(假设应用的名称叫Layer)

    模拟器应用沙盒的根路径在: (apple是用户名, 6.0是模拟器版本)

    /Users/apple/Library/Application Support/iPhone Simulator/6.0/Applications

    Document 保存应用运行时生成的需要持久化的数据,iTunes同步设备时会备份该目录。例如,游戏应用可将游戏存档保存在该目录

    temp 保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录

    Library/Caches 保存应用运行时生成的需要持久化的数据,iTunes同步设备时不会备份该目录。一般存储体积大、不需要备份的非重要数据

    Library/Preference: 保存应用的所有偏好设置,iOS的Settings(设置)应用会在该目录中查找应用的设置信息。iTunes同步设备时会备份该目录

    下面是示例代码:

     1 /** 保存数据*/
     2 - (IBAction)saveBtn
     3 {
     4     NSLog(@"保存");
     5     //1.获取沙盒根路径
     6     NSString *homePath = NSHomeDirectory();
     7     //2.document路径
     8     NSString *path = [homePath stringByAppendingPathComponent:@"Documents"];
     9     //3.新建数据
    10     NSArray *array = [NSArray arrayWithObjects:@"nan",@(22), nil];
    11     NSDictionary *dict = @{@"sss":@"sddd",@"ssssaw":@(1222)};
    12     
    13     
    14     //4.存储数据
    15     NSString *fullPath1 = [path stringByAppendingPathComponent:@"data1.plist"];
    16     NSString *fullPath2 = [path stringByAppendingPathComponent:@"data2.plist"];
    17     
    18     [array writeToFile:fullPath1 atomically:YES]; //数组写入plist
    19     [dict writeToFile:fullPath2 atomically:YES];
    20     
    21     NSLog(@"dict - %@",dict);
    22 }
    23 
    24 /** 读取数据*/
    25 - (IBAction)readBtn
    26 {
    27     //1.获取home目录
    28     NSString *home = NSHomeDirectory();
    29     //2.拼接Document目录
    30     NSString *path = [home stringByAppendingPathComponent:@"Documents"];
    31     //3.文件路径
    32     NSString *filePath1 = [path stringByAppendingPathComponent:@"data1.plist"];
    33     NSString *filePath2 = [path stringByAppendingPathComponent:@"data2.plist"];
    34     //读取文件
    35     NSArray *array = [NSArray arrayWithContentsOfFile:filePath1];
    36     NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:filePath2];
    37     NSLog(@"array - %@, dict - %@",array , dict);
    38 }

    缺点:只能存储含有 writeToFile:方法的对象,如NSDictionary,NSArray等.

    2.偏好设置 -- 存放目录 Library/Preference:

    很多iOS应用都支持偏好设置,比如保存用户名、密码、字体大小等设置,iOS提供了一套标准的解决方案来为应用加入偏好设置功能
    每个应用都有个NSUserDefaults实例,通过它来存取偏好设置
    比如,保存用户名、字体大小、是否自动登录

    下面是示例代码

    /** 保存数据*/
    - (IBAction)save
    {
        // 1.利用NSUserDefaults,就能直接访问软件的偏好设置(Library/Preferences)是个单例对象
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        //2.存储数据
        [defaults setObject:@"sd" forKey:@"user"];//其中要保存的数据是setObject:@"sd",@“sd”是数据,forKey:@"user"是以user的键值保存的,
      /**
        key - value 
        @"user" - @"sd" 
      */
    [defaults setObject:
    @"123w" forKey:@"test"]; [defaults setInteger:20 forKey:@"age"]; [defaults setBool:YES forKey:@"auto_login"]; //3.立刻同步(相当于更新数据) [defaults synchronize]; } /** 读取数据*/ - (IBAction)read { //1.建立NSUserDefaults对象 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; //2.读取数据 NSString *user = [defaults objectForKey:@"user"]; NSString *test = [defaults objectForKey:@"test"]; NSInteger age = [defaults integerForKey:@"age"]; BOOL autoLogin = [defaults boolForKey:@"auto_login"]; NSLog(@"user - %@ test - %@ age - %d autoLogin - %d ,",user,test,age,autoLogin); }

    //下面是解档归档基本OC对象
    - (void)test
    {

      NSString *mName = @"zhangsan";

     // 获取doc的目录

       NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    
    

        // 拼接保存的路径

    
    

        NSString *filePath = [docPath stringByAppendingPathComponent:@"dataList"];

    
    

        

    
    

        

    
    

    //    NSData *mData = [mName dataUsingEncoding:NSUTF8StringEncoding];

    
    

        

    
    

        [NSKeyedArchiver archiveRootObject:mName toFile:filePath];

    
    

        

    
    

        NSString *testName = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];

    
    

        

    
    

        NSLog(@"解档出来的数据是 ----- %@",testName);


    }


    注意:UserDefaults设置数据时,不是立即写入,而是根据时间戳定时地把缓存中的数据写入本地磁盘。所以调用了set方法之后数据有可能还没有写入磁盘应用程序就终止了。出现以上问题,可以通过调用synchornize方法强制写入[defaults synchornize];

    缺点:本质还是plist文件存储,相对于plist文件存储来讲存储数据更快捷.

    3.NSKeyedArchiver(NSCoding)

    如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,可以直接用NSKeyedArchiver进行归档和恢复
    不是所有的对象都可以直接用这种方法进行归档,只有遵守了NSCoding协议的对象才可以
    NSCoding协议有2个方法:
    encodeWithCoder:

    每次归档对象时,都会调用这个方法。一般在这个方法里面指定如何归档对象中的每个实例变量,可以使用encodeObject:forKey:方法归档实例变量

    initWithCoder:

    每次从文件中恢复(解码)对象时,都会调用这个方法。一般在这个方法里面指定如何解码文件中的数据为对象的实例变量,可以使用decodeObject:forKey方法解码实例变量

    示例代码

     1 #import <Foundation/Foundation.h>
     2 
     3 @interface Person : NSObject <NSCoding>
     4 
     5 @property (nonatomic , copy) NSString *name;
     6 @property (nonatomic , assign) int age;
     7 @property (nonatomic , assign) double height;
     8 
     9 @end
    10 
    11 
    12 #import "Person.h"
    13 
    14 @implementation Person
    15 
    16 //归档的时候调用
    17 /** 将某个对象写入文件的时候会调用,在这个方法中说明哪些对象的哪些属性需要存储*/
    18 - (void)encodeWithCoder:(NSCoder *)enCoder
    19 {
    20     NSLog(@"enCoder - %@",enCoder);
    21     [enCoder encodeObject:self.name forKey:@"name"];
    22     [enCoder encodeInt:self.age forKey:@"age"];
    23     [enCoder encodeDouble:self.height forKey:@"height"];
    24     
    25 }
    26 
    27 /** 解档时候调用,在这个方法中说清楚哪些属性要解档*/
    28 - (id)initWithCoder:(NSCoder *)decoder
    29 {
    30     if (self = [super init])
    31     {
    32         //读取文件内容
    33         self.name = [decoder decodeObjectForKey:@"name"];
    34         self.age = [decoder decodeIntForKey:@"age"];
    35         self.height = [decoder decodeDoubleForKey:@"height"];
    36         
    37     }
    38     
    39     return self;
    40 }
    41 
    42 
    43 @end
    44 
    45 
    46 #import "SDViewController.h"
    47 #import "Person.h"
    48 
    49 @interface SDViewController ()
    50 
    51 @end
    52 
    53 @implementation SDViewController
    54 
    55 - (void)viewDidLoad
    56 {
    57     [super viewDidLoad];
    58     
    59     
    60 }
    61 
    62 - (IBAction)save
    63 {
    64     //1.数据对象
    65     Person *p1 = [[Person alloc] init];
    66     p1.name = @"王麻子";
    67     p1.age = 20;
    68     p1.height = 1.98;
    69     Person *p2 = [[Person alloc] init];
    70     p2.name = @"李四";
    71     p2.age = 56;
    72     p2.height = 1.68;
    73     //2.归档数据对象
    74     //2.1获得文件的Documents全路径
    75     NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
    76     //2.2获得文件的全路径
    77     NSString *path = [doc stringByAppendingPathComponent:@"person.txt"];
    78     //2.3将对象归档
    79     [NSKeyedArchiver archiveRootObject:p1 toFile:path];
    80     
    81 }
    82 - (IBAction)read
    83 {
    84     // 1.获得Documents的全路径
    85     NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    86     // 2.获得文件的全路径
    87     NSString *path = [doc stringByAppendingPathComponent:@"person.txt"];
    88     // 3.从文件中读取Person对象
    89     Person *p3 = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
    90     
    91     NSLog(@"%@ %d %f", p3.name, p3.age, p3.height);
    92 
    93 }
    94 
    95 
    96 @end

    NSKeyedArchiver-归档对象的注意:

    如果父类也遵守了NSCoding协议,请注意:应该在encodeWithCoder:方法中加上一句[super encodeWithCode:encode];确保继承的实例变量也能被编码,
    即也能被归档应该在initWithCoder:方法中加上一句self = [super initWithCoder:decoder];确保继承的实例变量也能被解码,即也能被恢复
     
    但有时候可能想将多个对象写入到同一个文件中,那么就要使用NSData来进行归档对象NSData可以为一些数据提供临时存储空间,以便随后写入文件,或者存放从磁盘读取的文件内容。
    示例代码
      1 Person.h里面
      2 
      3 #import <Foundation/Foundation.h>
      4 
      5 @interface Person : NSObject <NSCoding>
      6 
      7 @property (nonatomic , copy) NSString *name;
      8 @property (nonatomic , assign) int age;
      9 @property (nonatomic , assign) double height;
     10 
     11 @end
     12 
     13 Person.m里面
     14 #import "Person.h"
     15 
     16 @implementation Person
     17 
     18 //归档的时候调用
     19 /** 将某个对象写入文件的时候会调用,在这个方法中说明哪些对象的哪些属性需要存储*/
     20 - (void)encodeWithCoder:(NSCoder *)enCoder
     21 {
     22     NSLog(@"enCoder - %@",enCoder);
     23     [enCoder encodeObject:self.name forKey:@"name"];
     24     [enCoder encodeInt:self.age forKey:@"age"];
     25     [enCoder encodeDouble:self.height forKey:@"height"];
     26     
     27 }
     28 
     29 /** 解档时候调用,在这个方法中说清楚哪些属性要解档*/
     30 - (id)initWithCoder:(NSCoder *)decoder
     31 {
     32     if (self = [super init])
     33     {
     34         //读取文件内容
     35         self.name = [decoder decodeObjectForKey:@"name"];
     36         self.age = [decoder decodeIntForKey:@"age"];
     37         self.height = [decoder decodeDoubleForKey:@"height"];
     38         
     39     }
     40     
     41     return self;
     42 }
     43 
     44 
     45 @end
     46 
     47 SDViewController.m里面
     48 
     49 #import "SDViewController.h"
     50 #import "Person.h"
     51 
     52 @interface SDViewController ()
     53 
     54 @end
     55 
     56 @implementation SDViewController
     57 
     58 - (void)viewDidLoad
     59 {
     60     [super viewDidLoad];
     61     // Do any additional setup after loading the view, typically from a nib.
     62     
     63 }
     64 
     65 - (void)didReceiveMemoryWarning
     66 {
     67     [super didReceiveMemoryWarning];
     68     // Dispose of any resources that can be recreated.
     69 }
     70 
     71 
     72 - (IBAction)save
     73 {
     74     //1.数据对象
     75     Person *p1 = [[Person alloc] init];
     76     p1.name = @"王麻子";
     77     p1.age = 20;
     78     p1.height = 1.98;
     79     Person *p2 = [[Person alloc] init];
     80     p2.name = @"李四";
     81     p2.age = 56;
     82     p2.height = 1.68;
     83     //2.归档数据对象
     84     //2.1获得文件的Documents全路径
     85     NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
     86     //2.2获得文件的全路径
     87     NSString *path = [doc stringByAppendingPathComponent:@"person.txt"];
     88 //    //2.3将对象归档
     89 //    [NSKeyedArchiver archiveRootObject:p1 toFile:path];
     90 //    
     91     // 新建一块可变数据区
     92     NSMutableData *data = [NSMutableData data];
     93     // 将数据区连接到一个NSKeyedArchiver对象
     94     NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
     95     [archiver encodeObject:p1 forKey:@"person1"];
     96     [archiver encodeObject:p2 forKey:@"person2"];
     97     // 存档完毕(一定要调用这个方法)
     98     [archiver finishEncoding];
     99     //将存档的数据写入文件
    100     [data writeToFile:path atomically:YES];
    101 
    102 }
    103 - (IBAction)read
    104 {
    105     // 1.获得Documents的全路径
    106     NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    107     // 2.获得文件的全路径
    108     NSString *path = [doc stringByAppendingPathComponent:@"person.txt"];
    109     // 3.从文件中读取Student对象
    110 //    Person *p3 = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
    111     NSData *data = [NSData dataWithContentsOfFile:path];
    112     
    113     // 根据数据,解析成一个NSKeyedUnarchiver对象
    114     NSKeyedUnarchiver *unchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    115     Person *p1 = [unchiver decodeObjectForKey:@"person1"];
    116     Person *p2 = [unchiver decodeObjectForKey:@"person2"];
    117     [unchiver finishDecoding];
    118     NSLog(@"%@ %d %f", p1.name, p1.age, p1.height);
    119     NSLog(@"%@ %d %f", p2.name, p2.age, p2.height);
    120     
    121 }
    122 
    123 
    124 
    125 @end

    NSCoder.h

     

    - (void)encodeValueOfObjCType:(const char *)type at:(const void *)addr; //解档C类型数据,addr传入地址

    - (void)encodeDataObject:(NSData *)data; //归档一个NSData型对象

    - (void)decodeValueOfObjCType:(const char *)type at:(void *)data; ////解档C类型数据

    - (NSData *)decodeDataObject;//解档一个NSData型对象

     

    @end

     

    @interface NSCoder (NSExtendedCoder)

     

    /** 归档相关函数*/

    - (void)encodeObject:(id)object;

    - (void)encodeRootObject:(id)rootObject;

    - (void)encodeBycopyObject:(id)anObject;

    - (void)encodeByrefObject:(id)anObject;

    - (void)encodeConditionalObject:(id)object;

    - (void)encodeValuesOfObjCTypes:(const char *)types, ...;

    - (void)encodeArrayOfObjCType:(const char *)type count:(NSUInteger)count at:(const void *)array;

    - (void)encodeBytes:(const void *)byteaddr length:(NSUInteger)length;

     

    /** 解档相关函数*/

    - (id)decodeObject;

    - (void)decodeValuesOfObjCTypes:(const char *)types, ...;

    - (void)decodeArrayOfObjCType:(const char *)itemType count:(NSUInteger)count at:(void *)array;

    - (void *)decodeBytesWithReturnedLength:(NSUInteger *)lengthp NS_RETURNS_INNER_POINTER;

     

     

    - (unsigned)systemVersion;

     

    //是否遵循KeyedCoding

    - (BOOL)allowsKeyedCoding;

     

    /** 归档相关函数*/

    - (void)encodeObject:(id)objv forKey:(NSString *)key;

    - (void)encodeConditionalObject:(id)objv forKey:(NSString *)key;

    - (void)encodeBool:(BOOL)boolv forKey:(NSString *)key;

    - (void)encodeInt:(int)intv forKey:(NSString *)key;

    - (void)encodeInt32:(int32_t)intv forKey:(NSString *)key;

    - (void)encodeInt64:(int64_t)intv forKey:(NSString *)key;

    - (void)encodeFloat:(float)realv forKey:(NSString *)key;

    - (void)encodeDouble:(double)realv forKey:(NSString *)key;

    - (void)encodeBytes:(const uint8_t *)bytesp length:(NSUInteger)lenv forKey:(NSString *)key;

     

    /** 解档相关函数*/

    - (BOOL)containsValueForKey:(NSString *)key;

    - (id)decodeObjectForKey:(NSString *)key;

    - (BOOL)decodeBoolForKey:(NSString *)key;

    - (int)decodeIntForKey:(NSString *)key;

    - (int32_t)decodeInt32ForKey:(NSString *)key;

    - (int64_t)decodeInt64ForKey:(NSString *)key;

    - (float)decodeFloatForKey:(NSString *)key;

    - (double)decodeDoubleForKey:(NSString *)key;

    - (const uint8_t *)decodeBytesForKey:(NSString *)key returnedLength:(NSUInteger *)lengthp NS_RETURNS_INNER_POINTER;   // returned bytes immutable!

     

    - (void)encodeInteger:(NSInteger)intv forKey:(NSString *)key NS_AVAILABLE(10_5, 2_0);

    - (NSInteger)decodeIntegerForKey:(NSString *)key NS_AVAILABLE(10_5, 2_0);

     

    // Returns YES if this coder requires secure coding. Secure coders check a list of allowed classes before decoding objects, and all objects must implement NSSecureCoding.

    //是否安全解档

    - (BOOL)requiresSecureCoding NS_AVAILABLE(10_8, 6_0);

     

    SQLite3 
    
    SQLite3是一款开源的嵌入式关系型数据库,可移植性好、易使用、内存开销小.SQLite3是无类型的,意味着你可以保存任何类型的数据到任意表的任意字段中。
     数据库语句
    
    /*简单约束*/
    
     //如果表不存在就创建一张t_student的表(id为主键,自动增长,name text类型,age integer类型);
    
    CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER);
    
     //如果表不存在就创建一张t_student的表(id为主键,自动增长,name text类型不能为空,age integer类型不能为空);
    
    CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age INTEGER NOT NULL);
    
     //如果表不存在就创建一张t_student的表(id为主键,自动增长,name text类型,并且每一个是唯一的,age integer类型不能为空);
    
    CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE, age INTEGER);
    
    //如果表不存在就创建一张t_student的表(id为主键,自动增长,name text类型,age integer类型默认为1);
    
    CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER DEFAULT 1);
    
     
    
    /*分页*/
    
    //先将表按照升序排,跳过最前面30条语句,然后取10条记录
    
    SELECT * FROM t_student ORDER BY id ASC LIMIT 30, 10;
    
     
    
    /*排序*/
    
    //取出表中score > 50的数据并按照降序排列
    
    SELECT * FROM t_student WHERE score > 50 ORDER BY age DESC;
    
    //取出表中score<50的数据并按照升序排列,score>50的数据按照降序排列
    
    SELECT * FROM t_student WHERE score < 50 ORDER BY age ASC , score DESC;
    
     
    
    /*计量*/
    
    //统计表中age > 50的个数
    
    SELECT COUNT(*) FROM t_student WHERE age > 50;
    
     
    
    /*别名*/
    
    //将name 命名为 myName, age 命名为 myAge, score 命名为myScore
    
    SELECT name as myName, age as myAge, score as myScore FROM t_student;
    
    //将name 命名为 myName, age 命名为 myAge, score 命名为myScore
    
    SELECT name myName, age myAge, score myScore FROM t_student;
    
    //给t_student表起个别名叫做s,利用s来引用表中的字段,取出age > 50 的数据,将name 命名为 myName, age 命名为 myAge, score 命名为myScore
    
    SELECT s.name myName, s.age myAge, s.score myScore FROM t_student s WHERE s.age > 50;
    
     
    
    /*查询*/
    
    //从表中查询name,age,score
    
    SELECT name, age, score FROM t_student;
    
    //查询整张表
    
    SELECT * FROM t_student;
    
     
    
    /*修改指定数据*/
    
    //从表中取出age = 10 的那条数据,将name 字段值设为MM
    
    UPDATE t_student SET name = 'MM' WHERE age = 10;
    
    /从表中取出age = 7 的那条数据,将name 字段值设为WW
    
    UPDATE t_student SET name = 'WW' WHERE age is 7;
    
    //取出表中age < 20 的数据,并将name 全部设置为XXOO
    
    UPDATE t_student SET name = 'XXOO' WHERE age < 20;
    
    //取出表中age < 50 并且 score > 10的数据,将满足条件的每一条数据中的name字段设置为NNMM
    
    UPDATE t_student SET name = 'NNMM' WHERE age < 50 and score > 10;
    
     
    
    /*删除数据*/
    
    //删除表中的数据
    
    DELETE FROM t_student;
    
     
    
    /*更新数据*/
    
    //将表中的name字段全部设置为MM
    
    UPDATE t_student SET name = 'MM';
    
     
    
    /*插入数据*/
    
    //往表中插入一条数据(name = jonathan , age = 28, score = 100)
    
     INSERT INTO t_student(age, score, name) VALUES ('28', 100, 'jonathan');
    
    //往表中插入一条数据(name = lee , age = 28)
    
     INSERT INTO t_student(name, age) VALUES ('lee', '28');
    
    //往表中插入一条数据(score =  100)
    
     INSERT INTO t_student(score) VALUES (100);
    
     
    
    /*添加主键*/
    
    //如果表不存在就创建一张表,id为主键自动增长,integer类型,name 为text类型,age 为integer类型,score为浮点类型
    
    CREATE TABLE IF NOT EXISTS t_student (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, score REAL);
    
    
    
    
    
     
    
    /*删除表*/
    
    //销毁t_student表
    
    DROP TABLE t_student;
    
    //如果表存在就销毁这张表
    
    DROP TABLE IF EXISTS t_student;
    
    
    
     
    
    /******************************************************  应 用  *****************************************************************/
    
    - (void)viewDidLoad
    
    {
    
        [super viewDidLoad];
    
        // 1.打开创建一个数据库
    
        NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    
        NSString *fileName = [path stringByAppendingPathComponent:@"t_student.sqlite"];
    
        int result = sqlite3_open(fileName.UTF8String, &_db);
    
        
    
        if (result == SQLITE_OK) {
    
            // 创建表
    
            const char *sql = "CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , name TEXT NOT NULL, age INTERGER NOT NULL);";
    
            char *error = nil;
    
            sqlite3_exec(self.db, sql, NULL, NULL, &error);
    
            if (error) {
    
                NSLog(@"创建失败");
    
            }else{
    
                NSLog(@"创建成功");
    
            }
    
        }else{
    
            NSLog(@"失败");
    
        }
    
        
    
    }
    
    /**
    
     *  增加
    
     */
    
    - (IBAction)insertBtnClick:(id)sender {
    
        for (int i = 0; i < 100; i++) {
    
            NSString *name = [NSString stringWithFormat:@"lee-%d", i];
    
            int age = arc4random_uniform(50) + 50;
    
            NSString *sql = [NSString stringWithFormat:@"INSERT INTO t_student(name, age) VALUES ('%@', %d);", name, age];
    
            char *error = nil;
    
            sqlite3_exec(self.db, sql.UTF8String, NULL, NULL, &error);
    
            
    
            if (error) {
    
                NSLog(@"创建失败");
    
            }else{
    
                NSLog(@"创建成功");
    
            }
    
        }
    
    }
    
    /**
    
     *  更新
    
     */
    
    - (IBAction)updateBtnClick:(id)sender {
    
        const char *sql = "UPDATE t_student SET name = 'DG';";
    
        char *error = nil;
    
        sqlite3_exec(self.db, sql, NULL, NULL, &error);
    
        
    
        if (error) {
    
            NSLog(@"更新失败");
    
        }else{
    
            NSLog(@"更新成功");
    
        }
    
    }
    
    /**
    
     *  删除
    
     */
    
    - (IBAction)deleteBtnClick:(id)sender {
    
        const char *sql = "DELETE FROM t_student;";
    
        char *error = nil;
    
        sqlite3_exec(self.db, sql, NULL, NULL, &error);
    
        if (error) {
    
            NSLog(@"删除失败");
    
        }else{
    
            NSLog(@"删除成功");
    
        }
    
    }
    
    /**
    
     *  查询
    
     */
    
    - (IBAction)selectBtnClick:(id)sender {
    
        const char *zSql = "SELECT * FROM t_student";
    
        sqlite3_stmt *stmt;
    
        // 查询前的准备, 检查sql语句是否正确
    
        int result = sqlite3_prepare_v2(self.db, zSql, -1, &stmt, NULL);
    
        if(result == SQLITE_OK) { // 准备完成,没有错误
    
            // 提取查询到得数据到stmt, 一次提取一条
    
            while(sqlite3_step(stmt) == SQLITE_ROW){
    
                // 取出提取到得记录(数据)中的第0列数据和第一列数据
    
                const unsigned char *name = sqlite3_column_text(stmt, 0);
    
                int age = sqlite3_column_int(stmt, 1);
    
                NSLog(@"%s, %d", name, age);
    
            }
    
        }
    
    }
    
    
    
    SqLite3小结
    
    1.打开数据库
    
    int sqlite3_open(
    
        const char *filename,   // 数据库的文件路径
    
        sqlite3 **.ppDb          // 数据库实例
    
    );
    
     
    
    2.执行任何SQL语句
    
    int sqlite3_exec(
    
        sqlite3*,                                  // 一个打开的数据库实例
    
        const char *sql,                           // 需要执行的SQL语句
    
        int (*callback)(void*,int,char**,char**),  // SQL语句执行完毕后的回调
    
        void *,                                    // 回调函数的第1个参数
    
        char **errmsg                              // 错误信息
    
    );
    
     
    
    3.检查SQL语句的合法性(查询前的准备)
    
    int sqlite3_prepare_v2(
    
        sqlite3 *db,            // 数据库实例
    
        const char *zSql,       // 需要检查的SQL语句
    
        int nByte,              // SQL语句的最大字节长度
    
        sqlite3_stmt **ppStmt,  // sqlite3_stmt实例,用来获得数据库数据
    
        const char **pzTail
    
    );
    
     
    
    4.查询一行数据
    
    int sqlite3_step(sqlite3_stmt*); // 如果查询到一行数据,就会返回SQLITE_ROW
    
     
    
    5.利用stmt获得某一字段的值(字段的下标从0开始)
    
    double sqlite3_column_double(sqlite3_stmt*, int iCol);  // 浮点数据
    
    int sqlite3_column_int(sqlite3_stmt*, int iCol); // 整型数据
    
    sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); // 长整型数据
    
    const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); // 二进制文本数据
    
    const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);  // 字符串数据
    
     
    
    6.SqLite3第三方框架FMDB使用小结
    
     FMDB是iOS平台的SQLite数据库框架,FMDB以OC的方式封装了SQLite的C语言API.
    
    FMDB的优点
    @1使用起来更加面向对象,省去了很多麻烦、冗余的C语言代码
    @2对比苹果自带的Core Data框架,更加轻量级和灵活
    
    @3提供了多线程安全的数据库操作方法,有效地防止数据混乱
    

      

     FMDB简单使用示例代码

    #import "CZViewController.h"
    #import "FMDB.h"
    
    @interface CZViewController ()
    - (IBAction)insertBtnClick;
    - (IBAction)updateBtnClick;
    - (IBAction)deleteBtnClick;
    - (IBAction)queryBtnClick;
    @property (nonatomic, strong) FMDatabase *db;
    @end
    
    @implementation CZViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // 0.获取沙盒路径
        NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
        NSString *fileName = [path stringByAppendingPathComponent:@"t_student.sqlite"];
        
        // 1.获得数据库对象
        self.db = [FMDatabase databaseWithPath:fileName];
        
        // 2.打开数据库
        if ([self.db open]) {
            NSLog(@"打开成功");
            // 2.1创建表
           BOOL success =  [self.db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_student (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT NOT NULL, age INTEGER NOT NULL);"];
            if (success) {
                NSLog(@"创建表成功");
            }else
            {
                NSLog(@"创建表失败");
            }
        }else
        {
            NSLog(@"打开失败");
        }
    }
    
    - (IBAction)insertBtnClick
    {
        
        for (int i = 0; i < 100; i++) {
            NSString *name = [NSString stringWithFormat:@"Jonathan-%d", i];
            int age = arc4random_uniform(1000);
            
            BOOL success = [self.db executeUpdate:@"INSERT INTO t_student(name , age) VALUES(?, ?);", name, @(age)];// 注意只能拼接对象类型
            if (success) {
                NSLog(@"添加成功");
            }else
            {
                NSLog(@"添加失败");
            }
        }
    }
    
    - (IBAction)updateBtnClick
    {
        BOOL success = [self.db executeUpdate:@"UPDATE t_student SET name = 'JACK' WHERE age < 50"];
        if (success) {
            NSLog(@"修改成功");
        }else
        {
            NSLog(@"修改失败");
        }
    
    }
    - (IBAction)deleteBtnClick
    {
        BOOL success = [self.db executeUpdate:@"DELETE FROM t_student WHERE age < ?;", @50];
        if (success) {
            NSLog(@"删除成功");
        }else
        {
            NSLog(@"删除失败");
        }
    
    }
    - (IBAction)queryBtnClick
    {
        // 1.查询
    //    FMResultSet *set = [self.db  executeQuery:@"SELECT id, name, age FROM t_student;"];
        FMResultSet *set = [self.db  executeQuery:@"SELECT * FROM t_student;"];
        
        // 2.取出数据
        while ([set next]) {
            
            // 取出姓名
    //       NSString *name = [set stringForColumnIndex:1];
            // 取出年龄
    //       int age = [set intForColumnIndex:2];
            NSString *name = [set stringForColumn:@"name"];
            int age = [set intForColumn:@"age"];
            NSLog(@"name = %@, age = %d", name, age);
        }
    }
    @end

    FMDB线程安全

    #import "CZViewController.h"
    #import "FMDB.h"
    
    @interface CZViewController ()
    - (IBAction)insertBtnClick;
    - (IBAction)updateBtnClick;
    - (IBAction)deleteBtnClick;
    - (IBAction)queryBtnClick;
    @property (nonatomic, strong) FMDatabase *db;
    @property (nonatomic, strong) FMDatabaseQueue *queue;
    @end
    
    @implementation CZViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // 0.获取沙盒路径
        NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
        NSString *fileName = [path stringByAppendingPathComponent:@"t_student.sqlite"];
        
        // 1.获得数据库对象
    //    self.db = [FMDatabase databaseWithPath:fileName];
        // 1.活的数据库队列对象
        self.queue = [FMDatabaseQueue databaseQueueWithPath:fileName];
        
        // 2.在数据库队列中执行线程安全的操作
        [self.queue inDatabase:^(FMDatabase *db) {
            if ([db open]) {
                // 2.1创建表
                BOOL success =  [db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_person (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT NOT NULL, money INTEGER NOT NULL);"];
                if (success) {
                    NSLog(@"创建表成功");
                }else
                {
                    NSLog(@"创建表失败");
                }
            }
    
        }];
    
    }
    
    - (IBAction)insertBtnClick
    {
        [self.queue inDatabase:^(FMDatabase *db) {
            [db executeUpdate:@"INSERT INTO t_person(name, money) VALUES('Zs', 1000)"];
            [db executeUpdate:@"INSERT INTO t_person(name, money) VALUES('LS', 1000)"];
        }];
    }
    
    - (IBAction)updateBtnClick
    {
        /*
        [self.queue inDatabase:^(FMDatabase *db) {
            [db beginTransaction]; // 开启事务
            [db executeUpdate:@"update t_person set money = 0 where name = 'Zs';"];
    //        [db rollback];// 主动回滚
            [db executeUpdate:@"update t_person set money = 2000 where name = 'LS';"];
            [db commit];// 提交事务
        }];
         */
        
        [self.queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
             [db executeUpdate:@"update t_person set money = 0 where name = 'Zs';"];
            NSLog(@"主动回滚");
            *rollback = YES;
             [db executeUpdate:@"update t_person set money = 2000 where name = 'LS';"];
        }];
    
    }
    - (IBAction)deleteBtnClick
    {
       [self.queue inDatabase:^(FMDatabase *db) {
           BOOL success = [db executeUpdate:@"DELETE FROM t_student WHERE age < ?;", @50];
           if (success) {
               NSLog(@"删除成功");
           }else
           {
               NSLog(@"删除失败");
           }
       }];
    
    }
    - (IBAction)queryBtnClick
    {
        [self.queue inDatabase:^(FMDatabase *db) {
            // 1.查询
            FMResultSet *set = [db  executeQuery:@"SELECT * FROM t_student;"];
            
            // 2.取出数据
            while ([set next]) {
                NSString *name = [set stringForColumn:@"name"];
                int age = [set intForColumn:@"age"];
                NSLog(@"name = %@, age = %d", name, age);
            }
        }];
    
    }
    @end

     
  • 相关阅读:
    MySQL-LSN
    MySQL Binlog三种格式介绍及分析
    MySQL中的seconds_behind_master的理解
    MySQL的四种事务隔离级别
    pt-table-sync修复mysql主从不一致的数据
    MySQL主从不同步、数据不一致解决办法
    nginx的应用【静态代理、动静分离】
    Redis数据缓存淘汰策略【FIFO 、LRU、LFU】
    Java基本知识点o(1), o(n), o(logn), o(nlogn)的了解
    JS函数篇【2】
  • 原文地址:https://www.cnblogs.com/ndyBlog/p/3962509.html
Copyright © 2011-2022 走看看