首页 > 技术文章 > FMDB存储模型对象(以二进制存储)用NSKeyedArchiver archivedDataWithRootObject序列号,NSKeyedUnarchiver unarchiveObjectWithData反序列化(重点坑是sql语句@"insert into t_newsWithChannel (nwesName,newsType) values (?,?)")一定要用占位符

dujiahong 2017-03-28 13:39 原文

交友:微信号 dwjluck2013

一、封装FMDB单例

(1)JLFMDBHelp.h文件

 1 #import <Foundation/Foundation.h>
 2 #import <FMDatabase.h>
 3 
 4 @interface JLFMDBHelp : NSObject
 5 
 6 @property(nonatomic,strong)NSString *fileName;//数据库名
 7 
 8 @property(nonatomic,strong)FMDatabase *database; //数据库对象
 9 
10 + (JLFMDBHelp*)sharedFMDBHelp;
11 //数据库存储路径
12 - (NSString*)dbPath;
13 //打开数据库
14 - (void)openDB;
15 //关闭数据库
16 - (void)closeDB;
17 //创建表
18 - (void)dbCreateTable;
19 //插入
20 -(BOOL)insertDBWithData:(NSData *)newsData dbWithString:(NSString *)channelWithStr;
21 //查询
22 -(NSMutableArray *)selectDBWithChannel:(NSString *)channel;
23 //给数据库命名
24 - (void)createDBWithName:(NSString*)dbName;
25 
26 //无返回结果集的操作
27 - (BOOL)notResultSetWithSql:(NSString*)sql;
28 //查询操作
29 - (NSArray*)qureyWithSql:(NSString*)sql;
30 @end

(2)JLFMDBHelp.m文件

  1 #import "JLFMDBHelp.h"
  2 #import "JLMainViewsModel.h"
  3 
  4 @interface JLFMDBHelp()
  5 
  6 @end
  7 
  8 @implementation JLFMDBHelp
  9 
 10 + (JLFMDBHelp*)sharedFMDBHelp {
 11     static JLFMDBHelp *help = nil;
 12     static dispatch_once_t onceToken;
 13     dispatch_once(&onceToken, ^{
 14         help = [[JLFMDBHelp alloc] init];
 15     });
 16     return help;
 17 }
 18 
 19 #pragma amrk - 根据名称创建沙盒路径用来保存数据库文件
 20 - (NSString*)dbPath {
 21     //说明fileName不为空
 22     if (self.fileName.length) {
 23         //1.创建DB,路径
 24         NSString *documents = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
 25         NSString *filePath = [documents stringByAppendingPathComponent:@"channelNews.db"];
 26         return filePath;
 27     } else {
 28         return @"";
 29     }
 30 }
 31 
 32 #pragma mark - 让用户来命名数据库的名称
 33 - (void)createDBWithName:(NSString*)dbName {
 34     if (dbName.length == 0) {
 35         //是防止用户直接传值为nil 或者 NULL
 36         self.fileName = @"";
 37     }else{
 38         self.fileName = [dbName stringByAppendingString:@".db"];
 39     }
 40 }
 41 
 42 #pragma mark - 创建数据库对象
 43 //懒加载
 44 - (FMDatabase*)database {
 45     if (!_database) {
 46         _database = [FMDatabase databaseWithPath:[self dbPath]];
 47     }
 48     return _database;
 49 }
 50 #pragma mark - 判断是否存在表
 51 - (BOOL) isTableOK:(NSString *)tableName
 52 {
 53     NSString *sqlStr = [NSString stringWithFormat:@"select count(*) as 'count' from sqlite_master where type ='table' and tbl_name = '%@';",tableName];
 54     FMResultSet *rs = [self.database executeQuery:sqlStr];
 55     while ([rs next])
 56     {
 57         NSInteger count = [rs intForColumn:@"count"];
 58         NSLog(@"isTableOK %ld", (long)count);
 59         
 60         if (0 == count)
 61         {
 62             return NO;
 63         }
 64         else
 65         {
 66             return YES;
 67         }
 68     }
 69     return NO;
 70 }
 71 #pragma mark - 创建数据库表
 72 - (void)dbCreateTable {
 73     if([self.database open]){
 74         if (![self isTableOK:@"t_newsWithChannel"]) {
 75             NSString *sql = @"create table if not exists t_newsWithChannel (newsID integer primary key autoincrement,nwesName blob,newsType VARCHAR not null);";
 76             BOOL execResult = [self.database executeUpdate:sql];
 77             if(execResult){
 78                 NSLog(@"table ok");
 79             }else{
 80                 NSLog(@"table fail");
 81             }
 82         }
 83         [self closeDB];
 84     }else{
 85         NSLog(@"open fail");
 86     }
 87 }
 88 
 89 #pragma mark - 打开数据库的方法
 90 - (void)openDB {
 91     BOOL isOpen = [self.database open];
 92     if (isOpen) {
 93         NSLog(@"打开数据库成功");
 94     } else {
 95         NSLog(@"打开数据库失败");
 96     }
 97 }
 98 
 99 #pragma mark - 关闭数据库的方法
100 - (void)closeDB {
101     BOOL isClose = [self.database close];
102     if (isClose) {
103         NSLog(@"关闭数据库成功");
104     } else {
105         NSLog(@"关闭数据库失败");
106     }
107 }
108 //插入
109 -(BOOL)insertDBWithData:(NSData *)newsData dbWithString:(NSString *)channelWithStr{
110     [self.database open];
111     NSString *sql = [NSString stringWithFormat:@"insert into t_newsWithChannel (nwesName,newsType) values (?,?)"];
112     BOOL execResult = [self.database executeUpdate:sql,newsData,channelWithStr];
113     if(execResult){
114         NSLog(@"insert ok");
115         return YES;
116     }else{
117         NSLog(@"insert fail");
118         return NO;
119     }
120 }
121 //查询
122 -(NSMutableArray *)selectDBWithChannel:(NSString *)channel{
123     NSString *resultSql = [NSString stringWithFormat:@"select * from t_newsWithChannel where newsType = '%@'",channel];
124     FMResultSet *set = [self.database executeQuery:resultSql];
125     NSMutableArray *array = [NSMutableArray array];
126     while ([set next]) {
127         NSData *newsData = [set dataForColumn:@"nwesName"];
128         JLMainViewsModel *model = [NSKeyedUnarchiver unarchiveObjectWithData:newsData];
129         if (model) {
130             [array addObject:model];
131         }
132     }
133     return array;
134 }
135 @end

二、模型数据

(1)JLMainViewsModel.h文件

要遵守协议

@interface JLMainViewsModel : NSObject<NSCopying,NSCoding>

 

(2)JLMainViewsModel.m文件

 1 -(void)encodeWithCoder:(NSCoder *)aCoder{
 2     
 3     [aCoder encodeObject:self.fromSource forKey:@"fromSource"];
 4     [aCoder encodeObject:self.url forKey:@"url"];
 5     [aCoder encodeObject:self.title forKey:@"title"];
 6     [aCoder encodeObject:self.type forKey:@"type"];
 7     [aCoder encodeObject:self.newsTime forKey:@"newsTime"];
 8     [aCoder encodeObject:self.imageUrl forKey:@"imageUrl"];
 9     [aCoder encodeObject:self.imageArray forKey:@"imageArray"];
10     [aCoder encodeObject:self.bigImageUrl forKey:@"bigImageUrl"];
11     [aCoder encodeObject:self.bigImageArray forKey:@"bigImageArray"];
12     [aCoder encodeObject:self.recommend forKey:@"recommend"];
13     [aCoder encodeObject:self.exData forKey:@"exData"];
14     [aCoder encodeObject:self.newsType forKey:@"newsType"];
15     [aCoder encodeObject:self.style forKey:@"style"];
16     [aCoder encodeObject:self.gzh forKey:@"gzh"];
17     [aCoder encodeObject:self.uniqId forKey:@"uniqId"];
18     [aCoder encodeObject:self.subdesc forKey:@"subdesc"];
19     [aCoder encodeObject:self.autoplay forKey:@"autoplay"];
20     [aCoder encodeObject:self.fromicon forKey:@"fromicon"];
21     [aCoder encodeObject:self.webUrl forKey:@"webUrl"];
22 }
23 
24 -(id)initWithCoder:(NSCoder *)aDecoder{
25     if (self = [super init]) {
26         self.fromSource = [aDecoder decodeObjectForKey:@"fromSource"];
27         self.url = [aDecoder decodeObjectForKey:@"url"];
28         self.title = [aDecoder decodeObjectForKey:@"title"];
29         self.type = [aDecoder decodeObjectForKey:@"type"];
30         self.newsTime = [aDecoder decodeObjectForKey:@"newsTime"];
31         self.imageUrl = [aDecoder decodeObjectForKey:@"imageUrl"];
32         self.imageArray = [aDecoder decodeObjectForKey:@"imageArray"];
33         self.bigImageUrl = [aDecoder decodeObjectForKey:@"bigImageUrl"];
34         self.bigImageArray = [aDecoder decodeObjectForKey:@"bigImageArray"];
35         self.recommend = [aDecoder decodeObjectForKey:@"recommend"];
36         self.exData = [aDecoder decodeObjectForKey:@"exData"];
37         self.newsType = [aDecoder decodeObjectForKey:@"newsType"];
38         self.style = [aDecoder decodeObjectForKey:@"style"];
39         self.gzh = [aDecoder decodeObjectForKey:@"gzh"];
40         self.uniqId = [aDecoder decodeObjectForKey:@"uniqId"];
41         self.subdesc = [aDecoder decodeObjectForKey:@"subdesc"];
42         self.autoplay = [aDecoder decodeObjectForKey:@"autoplay"];
43         self.fromicon = [aDecoder decodeObjectForKey:@"fromicon"];
44         self.webUrl = [aDecoder decodeObjectForKey:@"webUrl"];
45     }
46     return self;
47 }
48 
49 - (id)copyWithZone:(NSZone *)zone
50 {
51     JLMainViewsModel *model = [[[self class] allocWithZone:zone]init];
52     return model;
53 }

三、存储数据  在网络请求成功后存储  只是存储时的代码

 1 //网络请求回调 成功
 2                 if(successBlock){
 3                     JLFMDBHelp *fmdbHelp = [JLFMDBHelp sharedFMDBHelp];
 4                     //数据库名
 5                     [fmdbHelp createDBWithName:@"t_newsWithChannel"];
 6                     //路径
 7                     NSString *filePath = [fmdbHelp dbPath];
 8                     //创建数据库表
 9                     [fmdbHelp dbCreateTable];
10                     
11                     FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:filePath];
12                     [queue inDatabase:^(FMDatabase *db) {
13                         [mArray enumerateObjectsUsingBlock:^(JLMainViewsModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
14                             //将数组转换成字符串
15                             NSData *newsData = [NSKeyedArchiver archivedDataWithRootObject:obj];
16                             //插入
17                             if ([fmdbHelp insertDBWithData:newsData dbWithString:chanl]) {
18                                 [fmdbHelp closeDB];
19                             }else{
20                                 [fmdbHelp closeDB];
21                             }
22                         }];
23                     }];
24 
25                     
26 //                    //1.获取存储的路径
27 //                    NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
28 //                    NSString *filePatha = [documents stringByAppendingPathComponent:@"newsModelWithArray.plist"];
29 //                    //归档
30 //                    [NSKeyedArchiver archiveRootObject:mArray toFile:filePatha];
31 //                    NSLog(@"路径-----%@",filePath);
32                     successBlock(mArray.copy);
33                 }

四、在需要用的vc中读取数据

 1 #pragma mark - 本地数据库中读取数据(模型对象)
 2 -(void)getdbDataSource{
 3     JLFMDBHelp *fmdbHelp = [JLFMDBHelp sharedFMDBHelp];
 4     //数据库名
 5     [fmdbHelp createDBWithName:@"channelNews"];
 6     //打开数据库
 7     [fmdbHelp openDB];
 8     
 9     NSMutableArray *mNewsArray = [fmdbHelp selectDBWithChannel:self.newsType];
10     NSLog(@"%@",mNewsArray);
11 }

重点:遇到的坑,存储数据的时候

NSString *sql = [NSString stringWithFormat:@"insert into t_newsWithChannel (nwesName,newsType) values (?,?)"];
values (?,?) 这里一定要用占位符,不能用values (%@,%@) 否则存储看不出问题,存储的数据却不对,反序列化的时候不会走model中的

-(id)initWithCoder:(NSCoder *)aDecoder方法

推荐阅读