网站国际化建设方案,广州和广州市注册公司区别,移动端网站开发的书,开发触屏版网站标签在iOS开发过程中#xff0c;不管是做什么应用#xff0c;都会碰到数据保存的问题#xff0c;你是用什么方法来持久保存数据的#xff1f;这是在几乎每一次关于iOS技术的交流或讨论都会被提到的问题#xff0c;而且大家对这个问题的热情持续高涨。本文主要从概念上把“数据… 在iOS开发过程中不管是做什么应用都会碰到数据保存的问题你是用什么方法来持久保存数据的这是在几乎每一次关于iOS技术的交流或讨论都会被提到的问题而且大家对这个问题的热情持续高涨。本文主要从概念上把“数据存储”这个问题进行剖析并且结合各自特点和适用场景进行全面抛析。。 NSUserDefaults NSUserDefaults被设计用来存储设备和应用的配置信息它通过一个工厂方法返回默认的、也是最常用到的实例对象。这个对象中储存了系统中用户的配置信息开发者可以通过这个实例对象对这些已有的信息进行修改也可以按照自己的需求创建新的配置项。 NSUserDefaults可以存储的数据类型包括NSData、NSString、NSNumber、NSDate、NSArray、NSDictionary。如果要存储其他类型则需要转换为前面的类型才能用NSUserDefaults存储。具体实现为 保存数据 NSUserDefaults *defaults [NSUserDefaults standardUserDefaults]; NSString *name ”default string“; [defaults setObject:firstName forKey:name]; //获得UIImage实例 UIImage *image[[UIImage alloc]initWithContentsOfFile:photo.jpg]; NSData *imageData UIImageJPEGRepresentation(image, 100);//UIImage对象转换成NSData [defaults synchronize]; //用synchronize方法把数据持久化到standardUserDefaults数据库 读取数据 NSUserDefaults *defaults [NSUserDefaults standardUserDefaults]; NSString *name [defaults objectForKey:name]; //根据键值取出name NSData *imageData [defaults dataForKey:image]; UIImage *Image [UIImage imageWithData:imageData]; //NSData转换为UIImage 归档解归档 NSKeyedArchiver采用归档的形式来保存数据该数据对象需要遵守NSCoding协议并且该对象对应的类必须提供encodeWithCoder:和initWithCoder:方法。前一个方法告诉系统怎么对对象进行编码而后一个方法则是告诉系统怎么对对象进行解码。例如对Possession对象归档保存。 定义Possession interface PossessionNSObjectNSCoding{//遵守NSCoding协议 NSString *name;//待归档类型 } implementation Possession -(void)encodeWithCoder:(NSCoder *)aCoder{ [aCoder encodeObject:name forKey:name]; } -(void)initWithCoder:(NSCoder *)aDecoder{ name[[aDeCoder decodeObjectforKey:name] retain]; } 归档操作 如果对Possession对象allPossession归档保存只需要NSCoder子类NSKeyedArchiver的方法archiveRootObject:toFile: 即可。 NSString *path [self possessionArchivePath]; [NSKeyedArchiver archiveRootObject:allPossessions toFile: path ] 解压操作 同样调用NSCoder子类NSKeyedArchiver的方法unarchiveRootObject:toFile: 即可 allPossessions [[NSKeyedUnarchiver unarchiveObjectWithFile:path] retain]; 缺点归档的形式来保存数据只能一次性归档保存以及一次性解压。所以只能针对小量数据而且对数据操作比较笨拙即如果想改动数据的某一小部分还是需要解压整个数据或者归档整个数据。 SQLite 用SQLite存储查询需求较多的数据,是我们开发中最常见的一种方式例如app的界面数据缓存离线缓存等。 第一步需要添加SQLite相关的库以及头文件在项目文件的Build Phases下找到Link Binary Library(ies)添加libsqlite3.0.dylib libsqlite3.dylib与前者的区别暂时不知两者应该差不多在项目文件中头文件或者源文件中添加头文件#import “/usr/include/sqlite3.h” 第二步开始使用SQLite NSArray *documentsPathsNSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask , YES); NSString *databaseFilePath[[documentsPaths objectAtIndex:0] stringByAppendingPathComponent:mydb]; //上面两句已经比较熟悉了吧 //打开数据库 if (sqlite3_open([databaseFilePath UTF8String], database)SQLITE_OK) { NSLog(sqlite dadabase is opened.); } else{ return;}//打开不成功就返回 在打开了数据库的前提下如果数据库没有表那就开始建表了哦 char *error; const char *createSqlcreate table(id integer primary key autoincrement, name text); if (sqlite3_exec(database, createSql, NULL, NULL, error)SQLITE_OK) { NSLog(create table is ok.); } else { NSLog(error: %s,error); sqlite3_free(error);//每次使用完毕清空error字符串提供给下一次使用 } 建表完成之后就开始插入记录 const char *insertSqlinsert into a person (name) values(‘gg’); if (sqlite3_exec(database, insertSql, NULL, NULL, error)SQLITE_OK) { NSLog(insert operation is ok.); } else { NSLog(error: %s,error); sqlite3_free(error);//每次使用完毕清空error字符串提供给下一次使用 } 下一步查询记录 const char *selectSqlselect id,name from a person; sqlite3_stmt *statement; if (sqlite3_prepare_v2(database,selectSql, -1, statement, nil)SQLITE_OK) { NSLog(select operation is ok.); } else { NSLog(error: %s,error); sqlite3_free(error); } while(sqlite3_step(statement)SQLITE_ROW) { int _idsqlite3_column_int(statement, 0); NSString *name(char*)sqlite3_column_text(statement, 1); NSLog(rowid %i, name %s,_id,name); } sqlite3_finalize(statement); 最后关闭数据库 sqlite3_close(database); 注意写入数据库字符串可以采用char方式而从数据库中取出char类型当char类型有表示中文字符时会出现乱码。这是因为数据库默认使用ascII编码方式。所以要想正确从数据库中取出中文需要用NSString来接收从数据库取出的字符串。 CoreData Core Data使用起来相对直接使用SQLite3的API而言更加的面向对象操作过程通常分为以下几个步骤 1.创建管理上下文 创建管理上下可以细分为加载模型文件-指定数据存储路径-创建对应数据类型的存储-创建管理对象上下方并指定存储。 经过这几个步骤之后可以得到管理对象上下文NSManagedObjectContext以后所有的数据操作都由此对象负责。同时如果是第一次创建上下文Core Data会自动创建存储文件例如这里使用SQLite3存储并且根据模型对象创建对应的表结构。下图为第一次运行生成的数据库及相关映射文件 为了方便后面使用NSManagedObjectContext对象可以作为单例或静态属性来保存下面是创建的管理对象上下文的主要代码 -(NSManagedObjectContext *)createDbContext{ NSManagedObjectContext *context; //打开模型文件参数为nil则打开包中所有模型文件并合并成一个 NSManagedObjectModel *model[NSManagedObjectModel mergedModelFromBundles:nil]; //创建解析器 NSPersistentStoreCoordinator *storeCoordinator[[NSPersistentStoreCoordinator alloc]initWithManagedObjectModel:model]; //创建数据库保存路径 NSString *dir[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; NSLog(%,dir); NSString *path[dir stringByAppendingPathComponent:myDatabase.db]; NSURL *url[NSURL fileURLWithPath:path]; //添加SQLite持久存储到解析器 NSError *error; [storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:error]; if(error){ NSLog(数据库打开失败错误:%,error.localizedDescription); }else{ context[[NSManagedObjectContext alloc]init]; context.persistentStoreCoordinatorstoreCoordinator; NSLog(数据库打开成功); } return context; } 2.查询数据 对于有条件的查询在Core Data中是通过谓词来实现的。首先创建一个请求然后设置请求条件最后调用上下文执行请求的方法。 -(void)addUserWithName:(NSString *)name screenName:(NSString *)screenName profileImageUrl:(NSString *)profileImageUrl mbtype:(NSString *)mbtype city:(NSString *)city{ //添加一个对象 User *us [NSEntityDescription insertNewObjectForEntityForName:User inManagedObjectContext:self.context]; us.namename; us.screenNamescreenName; us.profileImageUrlprofileImageUrl; us.mbtypembtype; us.citycity; NSError *error; //保存上下文 if (![self.context save:error]) { NSLog(添加过程中发生错误,错误信息%,error.localizedDescription); } } 如果有多个条件只要使用谓词组合即可那么对于关联对象条件怎么查询呢这里分为两种情况进行介绍 a.查找一个对象只有唯一一个关联对象的情况例如查找用户名为“Binger”的微博一个微博只能属于一个用户通过 - (NSArray )getStatusesByUserName:(NSString )name{ NSFetchRequest *request[NSFetchRequest fetchRequestWithEntityName:”Status”]; request.predicate[NSPredicate predicateWithFormat:”user.name%”,name]; NSArray *array[self.context executeFetchRequest:request error:nil]; return array; }ata生成的SQL语句会发现其实就是把Status表和User表进行了关联查询JOIN连接。 b.查找一个对象有多个关联对象的情况例如查找发送微博内容中包含“Watch”并且用户昵称为“小娜”的用户一个用户有多条微博此时可以充分利用谓词进行 -(NSArray )getUsersByStatusText:(NSString )text screenName:(NSString *)screenName{ NSFetchRequest *request[NSFetchRequest fetchRequestWithEntityName:”Status”]; request.predicate[NSPredicate predicateWithFormat:”text LIKE ‘Watch‘”,text]; NSArray *statuses[self.context executeFetchRequest:request error:nil]; NSPredicate *userPredicate [NSPredicate predicateWithFormat:user.screenName%,screenName]; NSArray *users [statuses filteredArrayUsingPredicate:userPredicate]; return users; 如果单纯查找微博中包含“Watch”的用户直接查出对应的微博然后通过每个微博的user属性即可获得用户此时就不用使用额外的谓词过滤条件。 3.插入数据 插入数据需要调用实体描述对象NSEntityDescription返回一个实体对象然后设置对象属性最后保存当前上下文即可。这里需要注意增、删、改操作完最后必须调用管理对象上下文的保存方法否则操作不会执行。 -(void)addUserWithName:(NSString *)name screenName:(NSString *)screenName profileImageUrl:(NSString *)profileImageUrl mbtype:(NSString *)mbtype city:(NSString *)city{ //添加一个对象 User *us [NSEntityDescription insertNewObjectForEntityForName:User inManagedObjectContext:self.context]; us.namename; us.screenNamescreenName; us.profileImageUrlprofileImageUrl; us.mbtypembtype; us.citycity; NSError *error; //保存上下文 if (![self.context save:error]) { NSLog(添加过程中发生错误,错误信息%,error.localizedDescription); } } 4.删除数据 删除数据可以直接调用管理对象上下文的deleteObject方法删除完保存上下文即可。注意删除数据前必须先查询到对应对象。 -(void)removeUser:(User *)user{ [self.context deleteObject:user]; NSError *error; if (![self.context save:error]) { NSLog(删除过程中发生错误错误信息%!,error.localizedDescription); } } 5.修改数据 修改数据首先也是取出对应的实体对象然后通过修改对象的属性最后保存上下文。 -(void)modifyUserWithName:(NSString *)name screenName:(NSString *)screenName profileImageUrl:(NSString *)profileImageUrl mbtype:(NSString *)mbtype city:(NSString *)city{ User *us[self getUserByName:name]; us.screenNamescreenName; us.profileImageUrlprofileImageUrl; us.mbtypembtype; us.citycity; NSError *error; if (![self.context save:error]) { NSLog(修改过程中发生错误,错误信息%,error.localizedDescription); } } 调试 虽然Core Data如果使用SQLite数据库操作最终转换为SQL操作但是调试起来却不想操作SQL那么方便。特别是对于初学者而言经常出现查询报错的问题如果能看到最终生成的SQL语句自然对于调试很有帮助。事实上在Xcode中是支持Core Data调试的具体操作Product-Scheme-Edit Scheme-Run-Arguments中依次添加两个参数注意参数顺序不能错-com.apple.CoreData.SQLDebug、1。然后在运行程序过程中如果操作了数据库就会将SQL语句打印在输出面板。 转载于:https://www.cnblogs.com/fengmin/p/5464392.html