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

     
  • 相关阅读:
    EntityFramework 启用迁移 EnableMigrations 报异常 "No context type was found in the assembly"
    JAVA 访问FTP服务器示例(2)
    NuGet Package Manager 更新错误解决办法
    JAVA 访问FTP服务器示例(1)
    RemoteAttribute 的使用问题
    诡异的 javascript 变量
    javascript apply用法
    Babun 中文乱码
    GSM呼叫过程
    转站博客园
  • 原文地址:https://www.cnblogs.com/ndyBlog/p/3962509.html
Copyright © 2011-2022 走看看