1、iOS开发者须知那几种数据持久化方案iOS开发者须知:那几种数据持久化方案概论所谓的持久化,就是将数据保存到硬盘中,使得在应用程序或机器重启后可以继续访问之前保存的数据。在iOS开发中,有很多数据持久化的方案,接下来我将尝试着介绍一下5种方案:plist文件(属性列表)preference(偏好设置)NSKeyedArchiver(归档)SQLite 3CoreData沙盒在介绍各种存储方法之前,有必要说明以下沙盒机制。iOS程序默认情况下只能访问程序自己的目录,这个目录被称为“沙盒”。1.结构既然沙盒就是一个文件夹,那就看看里面有什么吧。沙盒的目录结构如下:1. 应用程序包2. Docume
2、nts3. Library4. Caches5. Preferences6. tmp2.目录特性虽然沙盒中有这么多文件夹,但是没有文件夹都不尽相同,都有各自的特性。所以在选择存放目录时,一定要认真选择适合的目录。应用程序包: 这里面存放的是应用程序的源文件,包括资源文件和可执行文件。1. NSString*path=NSBundlemainBundlebundlePath;2. NSLog(%,path);Documents: 最常用的目录,iTunes同步该应用时会同步此文件夹中的内容,适合存储重要数据。1. NSString*path=NSSearchPathForDirectoriesI
3、nDomains(NSDocumentDirectory,NSUserDomainMask,YES).firstObject;2. NSLog(%,path);Library/Caches: iTunes不会同步此文件夹,适合存储体积大,不需要备份的非重要数据。1. NSString*path=NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES).firstObject;2. NSLog(%,path);Library/Preferences: iTunes同步该应用时会同步此文件夹中的内容,通常
4、保存应用的设置信息。1. tmp:iTunes不会同步此文件夹,系统可能在应用没运行时就删除该目录下的文件,所以此目录适合保存应用中的一些临时文件,用完就删除。2. NSString*path=NSTemporaryDirectory();3. NSLog(%,path);plist文件plist文件是将某些特定的类,通过XML文件的方式保存在目录中。可以被序列化的类型只有如下几种:1. NSArray;2. NSMutableArray;3. NSDictionary;4. NSMutableDictionary;5. NSData;6. NSMutableData;7. NSString;
5、8. NSMutableString;9. NSNumber;10. NSDate;1.获得文件路径1. NSString*path=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES).firstObject;2. NSString*fileName=pathstringByAppendingPathComponent:123.plist;2.存储1. NSArray*array=123,456,789;2. arraywriteToFile:fileNameatomically:YES;3
6、.读取1. NSArray*result=NSArrayarrayWithContentsOfFile:fileName;2. NSLog(%,result);4.注意只有以上列出的类型才能使用plist文件存储。存储时使用writeToFile: atomically:方法。 其中atomically表示是否需要先写入一个辅助文件,再把辅助文件拷贝到目标文件地址。这是更安全的写入文件方法,一般都写YES。读取时使用arrayWithContentsOfFile:方法。Preference1.使用方法1. /1.获得NSUserDefaults文件2. NSUserDefaults*userD
7、efaults=NSUserDefaultsstandardUserDefaults;3. /2.向文件中写入内容4. userDefaultssetObject:AAAforKey:a;5. userDefaultssetBool:YESforKey:sex;6. userDefaultssetInteger:21forKey:age;7. /2.1立即同步8. userDefaultssynchronize;9. /3.读取文件10. NSString*name=userDefaultsobjectForKey:a;11. BOOLsex=userDefaultsboolForKey:se
8、x;12. NSIntegerage=userDefaultsintegerForKey:age;13. NSLog(%,%d,%ld,name,sex,age);2.注意偏好设置是专门用来保存应用程序的配置信息的,一般不要在偏好设置中保存其他数据。如果没有调用synchronize方法,系统会根据I/O情况不定时刻地保存到文件中。所以如果需要立即写入文件的就必须调用synchronize方法。偏好设置会将所有数据保存到同一个文件中。即preference目录下的一个以此应用包名来命名的plist文件。NSKeyedArchiver归档在iOS中是另一种形式的序列化,只要遵循了NSCoding
9、协议的对象都可以通过它实现序列化。由于决大多数支持存储数据的Foundation和Cocoa Touch类都遵循了NSCoding协议,因此,对于大多数类来说,归档相对而言还是比较容易实现的。1.遵循NSCoding协议NSCoding协议声明了两个方法,这两个方法都是必须实现的。一个用来说明如何将对象编码到归档中,另一个说明如何进行解档来获取一个新对象。遵循协议和设置属性1. /1.遵循NSCoding协议2. interfacePerson:NSObject/2.设置属性3. property(strong,nonatomic)UIImage*avatar;4. property(copy
10、,nonatomic)NSString*name;5. property(assign,nonatomic)NSIntegerage;6. end实现协议方法1. /解档2. -(id)initWithCoder:(NSCoder*)aDecoder3. if(superinit)4. self.avatar=aDecoderdecodeObjectForKey:avatar;5. self.name=aDecoderdecodeObjectForKey:name;6. self.age=aDecoderdecodeIntegerForKey:age;7. 8. returnself;9. 1
11、0. /归档11. -(void)encodeWithCoder:(NSCoder*)aCoder12. aCoderencodeObject:self.avatarforKey:avatar;13. aCoderencodeObject:self.nameforKey:name;14. aCoderencodeInteger:self.ageforKey:age;15. 特别注意如果需要归档的类是某个自定义类的子类时,就需要在归档和解档之前先实现父类的归档和解档方法。即 super encodeWithCoder:aCoder 和 super initWithCoder:aDecoder 方
12、法;2.使用需要把对象归档是调用NSKeyedArchiver的工厂方法 archiveRootObject: toFile: 方法。1. NSString*file=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES).firstObjectstringByAppendingPathComponent:person.data;2. Person*person=Personallocinit;3. person.avatar=self.avatarView.image;4. person.na
13、me=self.nameField.text;5. person.age=self.ageField.textintegerValue;6. NSKeyedArchiverarchiveRootObject:persontoFile:file;需要从文件中解档对象就调用NSKeyedUnarchiver的一个工厂方法 unarchiveObjectWithFile: 即可。1. NSString*file=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES).firstObjectstring
14、ByAppendingPathComponent:person.data;2. Person*person=NSKeyedUnarchiverunarchiveObjectWithFile:file;3. if(person)4. self.avatarView.image=person.avatar;5. self.nameField.text=person.name;6. self.ageField.text=NSStringstringWithFormat:%ld,person.age;7. 3.注意必须遵循并实现NSCoding协议保存文件的扩展名可以任意指定继承时必须先调用父类的归档
15、解档方法SQLite3之前的所有存储方法,都是覆盖存储。如果想要增加一条数据就必须把整个文件读出来,然后修改数据后再把整个内容覆盖写入文件。所以它们都不适合存储大量的内容。1.字段类型表面上SQLite将数据分为以下几种类型:integer : 整数real : 实数(浮点数)text : 文本字符串blob : 二进制数据,比如文件,图片之类的实际上SQLite是无类型的。即不管你在创表时指定的字段类型是什么,存储是依然可以存储任意类型的数据。而且在创表时也可以不指定字段类型。SQLite之所以什么类型就是为了良好的编程规范和方便开发人员交流,所以平时在使用时最好设置正确的字段类型!主键必须
16、设置成integer2. 准备工作准备工作就是导入依赖库啦,在iOS中要使用SQLite3,需要添加库文件:libsqlite3.dylib并导入主头文件,这是一个C语言的库,所以直接使用SQLite3还是比较麻烦的。3.使用创建数据库并打开操作数据库之前必须先指定数据库文件和要操作的表,所以使用SQLite3,首先要打开数据库文件,然后指定或创建一张表。1. /*2. *打开数据库并创建一个表3. */4. -(void)openDatabase5. /1.设置文件名6. NSString*filename=NSSearchPathForDirectoriesInDomains(NSDocu
17、mentDirectory,NSUserDomainMask,YES).firstObjectstringByAppendingPathComponent:person.db;7. /2.打开数据库文件,如果没有会自动创建一个文件8. NSIntegerresult=sqlite3_open(filename.UTF8String,&_sqlite3);9. if(result=SQLITE_OK)10. NSLog(打开数据库成功!);11. /3.创建一个数据库表12. char*errmsg=NULL;13. sqlite3_exec(_sqlite3,CREATETABLEIFNOTE
18、XISTSt_person(idintegerprimarykeyautoincrement,nametext,ageinteger),NULL,NULL,&errmsg);14. if(errmsg)15. NSLog(错误:%s,errmsg);16. else17. NSLog(创表成功!);18. 19. else20. NSLog(打开数据库失败!);21. 22. 执行指令使用 sqlite3_exec() 方法可以执行任何SQL语句,比如创表、更新、插入和删除操作。但是一般不用它执行查询语句,因为它不会返回查询到的数据。1. /*2. *往表中插入1000条数据3. */4. -
19、(void)insertData5. NSString*nameStr;6. NSIntegerage;7. for(NSIntegeri=0;i1000;i+)8. nameStr=NSStringstringWithFormat:Bourne-%d,arc4random_uniform(10000);9. age=arc4random_uniform(80)+20;10. NSString*sql=NSStringstringWithFormat:INSERTINTOt_person(name,age)VALUES(%,%ld),nameStr,age;11. char*errmsg=NU
20、LL;12. sqlite3_exec(_sqlite3,sql.UTF8String,NULL,NULL,&errmsg);13. if(errmsg)14. NSLog(错误:%s,errmsg);15. 16. 17. NSLog(插入完毕!);18. 查询指令前面说过一般不使用 sqlite3_exec() 方法查询数据。因为查询数据必须要获得查询结果,所以查询相对比较麻烦。示例代码如下:sqlite3_prepare_v2() : 检查sql的合法性sqlite3_step() : 逐行获取查询结果,不断重复,直到最后一条记录sqlite3_coloum_xxx() : 获取对应类型
21、的内容,iCol对应的就是SQL语句中字段的顺序,从0开始。根据实际查询字段的属性,使用sqlite3_column_xxx取得对应的内容即可。sqlite3_finalize() : 释放stm1. /*2. *从表中读取数据到数组中3. */4. -(void)readData5. NSMutableArray*mArray=NSMutableArrayarrayWithCapacity:1000;6. char*sql=selectname,agefromt_person;7. sqlite3_stmt*stmt;8. NSIntegerresult=sqlite3_prepare_v2
22、(_sqlite3,sql,-1,&stmt,NULL);9. if(result=SQLITE_OK)10. while(sqlite3_step(stmt)=SQLITE_ROW)11. char*name=(char*)sqlite3_column_text(stmt,0);12. NSIntegerage=sqlite3_column_int(stmt,1);13. /创建对象14. Person*person=PersonpersonWithName:NSStringstringWithUTF8String:nameAge:age;15. mArrayaddObject:person
23、;16. 17. self.dataList=mArray;18. 19. sqlite3_finalize(stmt);20. 4.总结总得来说,SQLite3的使用还是比较麻烦的,因为都是些c语言的函数,理解起来有些困难。不过在一般开发过程中,使用的都是第三方开源库 FMDB,封装了这些基本的c语言方法,使得我们在使用时更加容易理解,提高开发效率。FMDB1.简介FMDB是iOS平台的SQLite数据库框架,它是以OC的方式封装了SQLite的C语言API,它相对于cocoa自带的C语言框架有如下的优点:使用起来更加面向对象,省去了很多麻烦、冗余的C语言代码对比苹果自带的Core Data
24、框架,更加轻量级和灵活提供了多线程安全的数据库操作方法,有效地防止数据混乱注:FMDB的gitHub地址2.核心类FMDB有三个主要的类:FMDatabase一个FMDatabase对象就代表一个单独的SQLite数据库,用来执行SQL语句FMResultSet使用FMDatabase执行查询后的结果集FMDatabaseQueue用于在多线程中执行多个查询或更新,它是线程安全的3.打开数据库和c语言框架一样,FMDB通过指定SQLite数据库文件路径来创建FMDatabase对象,但FMDB更加容易理解,使用起来更容易,使用之前一样需要导入sqlite3.dylib。打开数据库方法如下:1.
25、 NSString*path=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES).firstObjectstringByAppendingPathComponent:person.db;2. FMDatabase*database=FMDatabasedatabaseWithPath:path;3. if(!databaseopen)4. NSLog(数据库打开失败!);5. 值得注意的是,Path的值可以传入以下三种情况:具体文件路径,如果不存在会自动创建空字符串,会在临时目录创建一个空的
26、数据库,当FMDatabase连接关闭时,数据库文件也被删除nil,会创建一个内存中临时数据库,当FMDatabase连接关闭时,数据库会被销毁4.更新在FMDB中,除查询以外的所有操作,都称为“更新”, 如:create、drop、insert、update、delete等操作,使用executeUpdate:方法执行更新1. /常用方法有以下3种:2. -(BOOL)executeUpdate:(NSString*)sql,.3. -(BOOL)executeUpdateWithFormat:(NSString*)format,.4. -(BOOL)executeUpdate:(NSStr
27、ing*)sqlwithArgumentsInArray:(NSArray*)arguments5. /示例6. databaseexecuteUpdate:CREATETABLEIFNOTEXISTSt_person(idintegerprimarykeyautoincrement,nametext,ageinteger);7. /或者8. databaseexecuteUpdate:INSERTINTOt_person(name,age)VALUES(?,?),Bourne,NSNumbernumberWithInt:42;5.查询查询方法也有3种,使用起来相当简单:1. -(FMResu
28、ltSet*)executeQuery:(NSString*)sql,.2. -(FMResultSet*)executeQueryWithFormat:(NSString*)format,.3. -(FMResultSet*)executeQuery:(NSString*)sqlwithArgumentsInArray:(NSArray*)arguments查询示例:1. /1.执行查询2. FMResultSet*result=databaseexecuteQuery:SELECT*FROMt_person;3. /2.遍历结果集4. while(resultnext)5. NSString*name=resultstringForColumn:name;6. intage=resultintForColumn:age;7. 6.线程安全在多个线程中同时使用一个FMDatabase实例是不明智的。不要让多个线程分享同一个FMDatabase实例,它无法在多个线程中同时使用。 如果在多个线程中同时使用一个FMDatabase实例,会造成数据混乱等问题。所以,请使用 FMDatabaseQueue,它是线程安全的。以下是使用方法:创建队列。
copyright@ 2008-2023 冰点文库 网站版权所有
经营许可证编号:鄂ICP备19020893号-2