iOS常用数据持久化

日期:2020-05-07编辑作者:Web前端

json_to_dart的使用

数据层一直是程序的核心结构之一,在iOS开发过程中通常需要对数据进行持久化缓存以保证在无网络情况下打开App后进行一些展示或缓存聊天记录等,这时候就需要持久化数据。

数据模型的使用

NSUserDefault

常用来存储一个简单的状态如是否第一次登陆

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];[userDefaults setBool:YES forKey:@"firstLogin"];[userDefaults synchronize];

类别json的分析

  • NSUserDefault
  • Plist文件存储
  • NSKeyedArchiver 归档
  • SQLite3

工厂构造函数

SQLite3

一般用来存储大量的内容并可单一的修改更新某一条缓存信息等。实际上SQLite是无类型的。即不管你在创表时指定的字段类型是什么,存储是依然可以存储任意类型的数据。而且在创表时也可以不指定字段类型。

开发中我一般使用FMDB第三方库来进行数据库操作,demo中例子就使用FMDB实现。

// 创建数据库- openDatabase{ NSString *filepath = [[VGFileManagerCommon getDocumentPath] stringByAppendingString:@"cache.db"]; FMDatabase *db = [FMDatabase databaseWithPath:filepath]; if ([db open]) { self.db = db; NSString *sql = @"CREATE TABLE IF NOT EXISTS CACHE  (uid INTEGER PRIMARY KEY,  url TEXT,  title TEXT)"; if (![self.db executeUpdate:sql]) { NSLog(@"execute sql %@ error %@",sql,self.db.lastError); } } else { NSLog(@"open database failed %@",filepath); }}#pragma mark - public- (NSArray <VGCacheModel *>*)fetchCacheModelWithLimit:(NSInteger)limit{ __block NSArray *result = nil; NSString *sql = nil; if  { sql = @"SELECT *FROM CACHE ORDER BY uid DESC LIMIT ?"; } db_sync_safe(^{ NSMutableArray <VGCacheModel *>*array = [NSMutableArray array]; FMResultSet *rs = [self.db executeQuery:sql, @]; while ([rs next]) { VGCacheModel *model = loadToDatabase; [array addObject:model]; } [rs close]; result = array; }); return result;}- saveModels:(NSArray <VGCacheModel *>*)models{ db_sync_safe(^{ if ([models count]) { [self.db beginTransaction]; for (VGCacheModel*model in models) { saveToDatabase(self.db, model); } [self.db commit]; } });}- updateModel:(VGCacheModel *)model{ NSString *sql = @"UPDATE CACHE SET TITLE = ? WHRER uid = ?"; db_async(^{ if (![self.db executeUpdate:sql, model.title, model.uid]) { NSLog(@"update failed sql %@",sql); } });}#pragma mark - save & loadstatic inline VGCacheModel * loadToDatabase(FMResultSet *resultSet){ NSInteger uid = [resultSet longLongIntForColumn:@"uid"]; NSString *URL = [resultSet stringForColumn:@"url"]; NSString *title = [resultSet stringForColumn:@"title"]; VGCacheModel *model = [[VGCacheModel alloc] init]; model.uid = uid; model.imageURL = URL; model.title = title; return model;}static inline void saveToDatabase(FMDatabase *db, VGCacheModel *model){ NSString *sql = @"INSERT OR REPLACE INTO CACHE(uid, url, title) VALUES"; if(![db executeUpdate:sql, @(model.uid), model.imageURL, model.title]){ NSLog(@"update failed sql %@",sql); }}#pragma mark - Queuedispatch_queue_t cacheDatabaseQueue(){ static dispatch_queue_t queue; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ queue = dispatch_queue_create(databaseQueue, 0); dispatch_queue_set_specific(queue, kDatabaseQueueSpecificKey, kDatabaseQueueSpecificKey, NULL); }); return queue;}typedef void(^dispatch_block);void db_sync_safe(dispatch_block block){ if (dispatch_get_specific(kDatabaseQueueSpecificKey)) { block(); } else { dispatch_sync(cacheDatabaseQueue { block; }}void db_async(dispatch_block block){ dispatch_async(cacheDatabaseQueue { block;}

文章中例子的完整代码Demo简单的实现了Plist、NSKeyedArchiver 归档、SQLite3 三种数据持久化VGCacheDemo

  • NSHipster NSFileManager
  • iOS中的数据持久化
  • 我要永远地记住你!(iOS中几种数据持久化方案)

写完这些,你就可以在控制台看到结果了。如果是第一次接触数据模型,可能还是稍微有些绕的。

数据持久化就是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称. 数据模型可以是任何数据结构或对象模型,存储模型可以是关系模型、XML、二进制流等。cmp和Hibernate只是对象模型到关系模型之间转换的不同实现。

import ‘../model/category.dart‘;void _getCategory() async{ await request(‘post‘, ‘getCategory‘).then((val){ var data = json.decode(val.toString()); //print(data); CategoryBigListModel list = CategoryBigListModel.formJson(data[‘data‘]); list.data.forEach((item) = print(item.mallCategoryName)); });}

NSKeyedArchiver 归档

归档只要遵循了NSCoding协议的对象都可以通过它实现序列化。平时项目中使用Mantle 来实现model层 Mantle已经实现了NSCoding协议

Demo中例子直接存储model 但建议还是把Model转换成JSON Dictionary 来存储load时再转换成model

+ (instancetype)store{ return [[self alloc] init];}- fetchItemsWithCompletion:(VGKeyedArchiverStoreFetchCompletionHandler)completion{ if ([VGFileManagerCommon isFileExistAtPath:[self savePath]]) { VGCacheModel *model = [self loadModel]; completion; }}- (VGCacheModel *)loadModel{ return [NSKeyedUnarchiver unarchiveObjectWithFile:[self savePath]];}- (NSString *)savePath{ NSString *path = @"keyedArchiverStore.bin"; return [[VGFileManagerCommon getDocumentPath] stringByAppendingPathComponent:path];}- saveModel:(VGCacheModel *)Model{ BOOL success = [NSKeyedArchiver archiveRootObject:Model toFile:[self savePath]]; if  { NSLog(@"Save Failed"); }}

这个只是单个的一个大类信息的模型,但我们是一个列表,这时候就需要制作一个列表的模型,而这个List里边是我们定义的CategoryBigModel模型。简单理解就是先定义一个单项模型,然后再定义个列表的模型。

NSFileManager

Plist 和 归档 使用文件操作存储需要用到NSFileManager,创建一个工具类来对App的文件进行操作

NSFileManager 是处理文件系统的 Foundation 框架的高级API。它抽象了 Unix 和 Finder 的内部构成,和 iCloud ubiquitous containers 一样, 提供了创建,读取,移动,拷贝以及删除本地或者网络驱动器上的文件或者目录的方法。

NSFileManager 是一个单例使用以下方法来获得

 + (NSFileManager *)defaultManager

www.129028.com金沙,NSFileManager常用方法就不多提了这里需要提的一点是线程注意。apple 中提到:

The methods of the shared NSFileManager object can be called from multiple threads safely. However, if you use a delegate to receive notifications about the status of move, copy, remove, and link operations, you should create a unique instance of the file manager object, assign your delegate to that object, and use that file manager to initiate your operations.

大概说一下意思就是共享的NSFileManager对象方法可以从多个线程调用是安全的。可是,如果使用委托通知的状态移动,复制,删除等等操作,应该创建一个唯一实例并使用该实例来开始你的操作。

如使用NSFileManagerDelegate时最好创建实例来进行操作

NSFileManager *fileManager = [[NSFileManager alloc] init];fileManager.delegate = delegate;NSURL *bundleURL = [[NSBundle mainBundle] bundleURL];NSArray *contents = [fileManager contentsOfDirectoryAtURL:bundleURL includingPropertiesForKeys:@[] options:NSDirectoryEnumerationSkipsHiddenFiles error:nil];for (NSString *filePath in contents) { [fileManager removeItemAtPath:filePath error:nil];}

下面是我开发中一些常用的文件操作方法

// 创建一个存储文件夹并获取路径+ (NSString *)getDocumentPath{ static NSString *documentPath = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); documentPath = [[NSString alloc]initWithFormat:@"%@/%@/",[paths objectAtIndex:0],FOLDER_FILE_NAME]; if (![[NSFileManager defaultManager] fileExistsAtPath:documentPath]) { [[NSFileManager defaultManager] createDirectoryAtPath:documentPath withIntermediateDirectories:NO attributes:nil error:nil]; } }); return documentPath;}// 文件大小+ (NSUInteger)getFileSizeAtFileName:(NSString*)fileName{ NSString *path = [[VGFileManagerCommon getDocumentPath] stringByAppendingPathComponent:fileName]; return [[[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil]fileSize];}// 文件是否存在+ isFileExistAtPath:(NSString*)filePath{ BOOL isExist = NO; isExist = [[NSFileManager defaultManager] fileExistsAtPath:filePath]; return isExist;}// 文件是否存在+ isFileExistAtFileName:(NSString*)fileName{ NSString *path = [[VGFileManagerCommon getDocumentPath] stringByAppendingPathComponent:fileName]; return [VGFileManagerCommon isFileExistAtPath:path];}// 删除文件+ deleteFileAtFileName:(NSString *)fileName{ NSFileManager *fileMgr = [NSFileManager defaultManager]; NSString *deletePath = [[VGFileManagerCommon getDocumentPath] stringByAppendingPathComponent:fileName]; NSError *err = nil; [fileMgr removeItemAtPath:deletePath error:&err]; return err != nil;}

其实转换成model类是有好处的,转换后可以减少上线后APP崩溃和出现异常,所以我们从这节课开始,要制作model类模型,然后用model的形式编辑UI界面。

Plist文件存储

Property List,属性列表文件,它是一种用来存储串行化后的对象的文件。属性列表文件的扩展名为.plist ,plist文件的实质为XML文件。

可以被序列化的类型只有如下几种:

NSArray NSMutableArrayNSDictionary NSMutableDictionaryNSData NSMutableDataNSString NSMutableStringNSNumberNSDate

在实际的开发中我一般存储NSArray和NSDictonary经过使用后建议使用JSON 存储 取出后转成模型,避免增减字段的问题

开发中例子

- fetchItemsWithCompletion:(VGPlistStoreFetchCompletionHandler)completion{ NSDictionary *cacheJson = [self loadCache]; if (completion) { completion(cacheJson); }}- (NSDictionary *)loadCache{ NSString *path = [self savePath]; if ([VGFileManagerCommon isFileExistAtPath:path]) { return [NSDictionary dictionaryWithContentsOfFile:path]; } return nil;}- (NSString *)savePath{ return [[VGFileManagerCommon getDocumentPath] stringByAppendingPathComponent:@"cache.plist"];}- saveJSON:(NSDictionary *)json{ if  { NSString *path = [self savePath]; [json writeToFile:path atomically:YES]; }}

使用数据模型就简单很多了。直接声明变量,调用formJson方法就可以了。直接在_getCategory()方法里。记得先引入数据模型类,然后用.的形式进行输出了。

在项目开发中我最常使用的持久化方式有:

我们先制作了一个大分类的Class,代码如下:

如果我们得到一个特别复杂的JSON,有时候会无从下手开始写Model,这时候就可以使用一些辅助工具。我认为json_to_dart是比较好用的一个。它可以直接把json转换成dart类,然后进行一定的修改,就可以快乐的使用了。工作中我拿到一个json,都是先操作一下,然后再改的。算是一个小窍门吧。

本文由www.129028.com金沙发布于Web前端,转载请注明出处:iOS常用数据持久化

关键词:

nginx负载均衡如何实现www.129028.com金沙?

什么是nginx? Nginx是一个免费的,开源的,高性能的服务器和反向代理服务器软件,同时它也可以为IMAP和POP3服务器代...

详细>>

最少编码原则

这的确是大多数程序员,甚至是那些高级程序员都很容易混淆的一个重点。作为一名程序员,编写代码无疑是你职业...

详细>>

CSS中cursor 鼠标指针光标样式

值 前面url()是自定义鼠标的样式,图像的地址,后面的参数是 css 标准的 cursor样式,(IE下面可以不需要) 出现版本...

详细>>

AJAX:如何处理书签和后退按钮(1)

或者如果你不喜欢onclick: window.onload = initialize;function initialize() { // initialize the DHTML History // framework dhtmlHistory.initial...

详细>>