李洪强iOS经典面试题144-数据存储

李洪强iOS经典面试题144-数据存储

 

数据存储

sqlite中插入特殊字符的方法和接收处处理方法。

除’其余的都是在特殊字符前面加“/”,而 ' -> '' 。方法:keyWord = keyWord.replace("/","//");css

什么是NSManagedObject模型?

NSManagedObjcet是NSObject的子类,Core Date的重要组成部分。是一个通用类,实现了Core Date模型层所需的基本功能,用户能够经过NSManagedObjcet创建本身的数据模型。html

你实现过多线程的Core Data么?NSPersistentStoreCoordinator,NSManagedObjectContext和NSManagedObject中的哪些须要在线程中建立或者传递?你是用什么样的策略来实现的?

1> CoreData是对SQLite数据库的封装 2> coreData中有三个对象是必须掌握的, NSManagedObject :只要定义一个类继承于该类就会建立一张与之对应的表, 也就是一个继承于该类的类就对应一张表. 每个经过继承该类建立出来的对象,都是该类对应的表中的一条数据 NSManagedObjectContext: 用于操做数据库, 只要有类它就能对数据库的表进行增删改查 NSPersistentStoreCoordinator: 决定数据存储的位置 (SQLite/XML/其它文件中) 3> Core data自己并非一个并发安全的架构因此在多线程中实现Core data会有问题.问题在于 >2.1 CoreData中的NSManagedObjectContext在多线程中不安全 >2.2若是想要多线程访问CoreData的话,最好的方法是一个线程一个NSManagedObjectContext >2.3每一个NSManagedObjectContext对象实例均可以使用同一个NSPersistentStoreCoordinator实例,这是由于NSManagedObjectContext会在便用NSPersistentStoreCoordinator前上锁

简单描述下客户端的缓存机制?

  • 缓存能够分为:内存数据缓存、数据库缓存、文件缓存
    • 每次想获取数据的时候
    • 先检测内存中有无缓存
    • 再检测本地有无缓存(数据库\文件)
    • 最终发送网络请求
    • 将服务器返回的网络数据进行缓存(内存、数据库、文件), 以便下次读取

      什么是序列化和反序列化,用来作什么

  • 序列化把对象转化为字节序列的过程
  • 反序列化把直接序列恢复成对象
  • 把对象写到文件或者数据库中,而且读取出来

OC中实现复杂对象的存储

  • 遵循NSCoding协议,实现复杂对象的存储,实现该协议后能够对其进行打包或者解包,转化为NSDate

iOS中经常使用的数据存储方式有哪些?

  1. 数据存储有四种方案,NSUserDefault,KeyChain,File,DB.
  2. 其中File有三种方式:plist,Archiver,Stream
  3. DB包括core Data和FMDB

说一说你对SQLite的认识

  • SQLite是目前主流的嵌入式关系型数据库,其最主要的特色就是轻量级、跨平台,当前不少嵌入式操做系统都将其做为数据库首选。git

  • 虽然SQLite是一款轻型数据库,可是其功能也毫不亚于不少大型关系数据库。github

  • 学习数据库就要学习其相关的定义、操做、查询语言,也就是你们平常说得SQL语句。和其余数据库相比,SQLite中的SQL语法并无太大的差异,所以这里对于SQL语句的内容不会过多赘述,你们能够参考SQLite中其余SQL相关的内容,这里仍是重点讲解iOS中如何使用SQLite构建应用程序。先看一下SQLite数据库的几个特色:面试

    • 基于C语言开发的轻型数据库
    • 在iOS中须要使用C语言语法进行数据库操做、访问(没法使用ObjC直接访问,由于libqlite3框架基于C语言编写)
    • SQLite中采用的是动态数据类型,即便建立时定义了一种类型,在实际操做时也能够存储其余类型,可是推荐建库时使用合适的类型(特别是应用须要考虑跨平台的状况时)
    • 创建链接后一般不须要关闭链接(尽管能够手动关闭)
  • 在iOS中操做SQLite数据库能够分为如下几步(注意先在项目中导入libsqlite3框架):
    • 打开数据库,利用sqlite3_open()打开数据库会指定一个数据库文件保存路径,若是文件存在则直接打开,不然建立并打开。打开数据库会获得一个sqlite3类型的对象,后面须要借助这个对象进行其余操做。
    • 执行SQL语句,执行SQL语句又包括有返回值的语句和无返回值语句。
    • 对于无返回值的语句(如增长、删除、修改等)直接经过sqlite3_exec()函数执行;
    • 对于有返回值的语句则首先经过sqlite3_prepare_v2()进行sql语句评估(语法检测),而后经过sqlite3_step()依次取出查询结果的每一行数据,对于每行数据均可以经过对应的sqlite3_column_类型()方法得到对应列的数据,如此反复循环直到遍历完成。固然,最后须要释放句柄。

说一说你对FMDB的认识

  • FMDB是一个处理数据存储的第三方框架,框架是对sqlite的封装,整个框架很是轻量级但又不失灵活性,并且更加面向对象。FMDB有以下几个特性:
    • FMDB既然是对于libsqlite3框架的封装,天然使用起来也是相似的,使用前也要打开一个数据库,这个数据库文件存在则直接打开不然会建立并打开。这里FMDB引入了一个MFDatabase对象来表示数据库,打开数据库和后面的数据库操做所有依赖此对象。
    • 对于数据库的操做跟前面KCDbManager的封装是相似的,在FMDB中FMDatabase类提供了两个方法executeUpdate:和executeQuery:分别用于执行无返回结果的查询和有返回结果的查询。固然这两个方法有不少的重载这里就不详细解释了。惟一须要指出的是,若是调用有格式化参数的sql语句时,格式化符号使用“?”而不是“%@”、等。
    • 咱们知道直接使用libsqlite3进行数据库操做实际上是线程不安全的,若是遇到多个线程同时操做一个表的时候可能会发生意想不到的结果。为了解决这个问题建议在多线程中使用FMDatabaseQueue对象,相比FMDatabase而言,它是线程安全的。
    • 将事务放到FMDB中去说并非由于只有FMDB才支持事务,而是由于FMDB将其封装成了几个方法来调用,不用本身写对应的sql而已。其实在在使用libsqlite3操做数据库时也是原生支持事务的(由于这里的事务是基于数据库的,FMDB仍是使用的SQLite数据库),只要在执行sql语句前加上“begin transaction;”执行完以后执行“commit transaction;”或者“rollback transaction;”进行提交或回滚便可。另外在Core Data中你们也能够发现,全部的增、删、改操做以后必须调用上下文的保存方法,其实自己就提供了事务的支持,只要不调用保存方法,以前全部的操做是不会提交的。在FMDB中FMDatabase有beginTransaction、commit、rollback三个方法进行开启事务、提交事务和回滚事务。

说一说你对Core Data的认识

Core Data使用起来相对直接使用SQLite3的API而言更加的面向对象,操做过程一般分为如下几个步骤:算法

  • 建立管理上下文
    建立管理上下能够细分为:加载模型文件->指定数据存储路径->建立对应数据类型的存储->建立管理对象上下方并指定存储。
    通过这几个步骤以后能够获得管理对象上下文NSManagedObjectContext,之后全部的数据操做都由此对象负责。同时若是是第一次建立上下文,Core Data会自动建立存储文件(例如这里使用SQLite3存储),而且根据模型对象建立对应的表结构。
  • 查询数据
    对于有条件的查询,在Core Data中是经过谓词来实现的。首先建立一个请求,而后设置请求条件,最后调用上下文执行请求的方法。
  • 插入数据
    插入数据须要调用实体描述对象NSEntityDescription返回一个实体对象,而后设置对象属性,最后保存当前上下文便可。这里须要注意,增、删、改操做完最后必须调用管理对象上下文的保存方法,不然操做不会执行。
  • 删除数据
    删除数据能够直接调用管理对象上下文的deleteObject方法,删除完保存上下文便可。注意,删除数据前必须先查询到对应对象。
  • 修改数据
    修改数据首先也是取出对应的实体对象,而后经过修改对象的属性,最后保存上下文。

OC中有哪些数据存储方式,各有什么区别?

  • OC中有四种数据存储方式:
    • NSUserDefaults,用于存储配置信息
    • SQLite,用于存储查询需求较多的数据
    • CoreData,用于规划应用中的对象
  • 使用基本对象类型定制的个性化缓存方案.
    • NSUserDefaults:对象中储存了系统中用户的配置信息,开发者能够经过这个实例对象对这些已有的信息进行修改,也 能够按照本身的需求建立新的配置项。
    • SQLite擅长处理的数据类型其实与NSUserDefaults差很少,也是基础类型的小数据,只是从组织形式上不一样。开发者能够以关系型数据库的方式组织数据,使用SQL DML来管理数据。通常来讲应用中的格式化的文本类数据能够存放在数据库 中,尤为是相似聊天记录、Timeline等这些具备条件查询和排序需求的数据。
    • CoreData是一个管理方案,它的持久化能够经过SQLite、XML或二进制文件储存。它能够把整个应用中的对象建模并进行自动化的管理。从归档文件还原模型时CoreData并非一次性把整个模型中的全部数据都载入内存,而是根据运行时状态,把被调用到的对象实例载入内存。框架会自动控制这个过程,从而达到控制内存消耗,避免浪费。 不管从设计原理仍是使用方法上看,CoreData都比较复杂。所以,若是仅仅是考虑缓存数据这个需求,CoreData绝对不是一个优选方案。
    • CoreData的使用场景在于:整个应用使用CoreData规划,把应用内的数据经过CoreData建模,彻底基于CoreData架构应用。
    • 使用基本对象类型定制的个性化缓存方案:从需求出发分析缓存数据有哪些要求:按Key查找,快速读取,写入不影响正常操做,不浪费内存,支持归档。这些都是基本需求,那么再进一步或许还须要固定缓存项数量,支持队列缓存,缓存过时等。
      数据存储这一块, 面试常问, 你经常使用哪种数据存储? 什么是序列化? sqlite是直接用它仍是用封装了它的第三方库? 尤为是会问sqlite和core data的区别?

iOS平台怎么作数据的持久化?coredata和sqlite有无必然联系?coredata是一个关系型数据库吗?

  • iOS中能够有四种持久化数据的方式: 属性列表、对象归档、SQLite3和Core Datasql

  • coredata可使你以图形界面的方式快速的定义app的数据模型,同时在你的代码中容易获取到它。数据库

  • coredata提供了基础结构去处理经常使用的功能,例如保存,恢复,撤销和重作,容许你在app中继续建立新的任务。编程

  • 在使用coredata的时候,你不用安装额外的数据库系统,由于coredata使用内置的sqlite数据库。数组

  • coredata将你app的模型层放入到一组定义在内存中的数据对象。

  • coredata会 追踪这些对象的改变,同时能够根据须要作相应的改变,例如用户执行撤销命令。

  • 当coredata在对你app数据的改变进行保存的时 候,core data会把这些数据归档,并永久性保存。

  • mac os x中sqlite库,它是一个轻量级功能强大的关系数据引擎,也很容易嵌入到应用程序。能够在多个平台使用,sqlite是一个轻 量级的嵌入式sql数据库编程。

  • 与coredata框架不一样的是,sqlite是使用程序式的,sql的主要的API来直接操做数据表。

  • Core Data不是一个关系型数据库,也不是关系型数据库管理系统(RDBMS)。

  • 虽然Core Dta支持SQLite做为一种存储类型, 但它不能使用任意的SQLite数据库。

  • Core Data在使用的过程种本身建立这个数据库。Core Data支持对1、对多的关系。

若是后期须要增长数据库中的字段怎么实现,若是不使用CoreData呢?

  • 编写SQL语句来操做原来表中的字段
  • 增长表字段:ALTER TABLE 表名 ADD COLUMN 字段名 字段类型;
  • 删除表字段:ALTER TABLE 表名 DROP COLUMN 字段名;
  • 修改表字段:ALTER TABLE 表名 RENAME COLUMN 旧字段名 TO 新字段名;

SQLite数据存储是怎么用?

  • 添加SQLite动态库:导入主头文件:#import <sqlite3.h>
  • 利用C语言函数建立\打开数据库,编写SQL语句

简单描述下客户端的缓存机制?

  • 缓存能够分为:内存数据缓存、数据库缓存、文件缓存
  • 每次想获取数据的时候
  • 先检测内存中有无缓存
  • 再检测本地有无缓存(数据库\文件)
  • 最终发送网络请求
  • 将服务器返回的网络数据进行缓存(内存、数据库、文件)以便下次读取

你实现过多线程的Core Data么?NSPersistentStoreCoordinator,NSManagedObjectContext和NSManagedObject中的哪些须要在线程中建立或者传递?你是用什么样的策略来实现的?

  • CoreData是对SQLite数据库的封装
  • CoreData中的NSManagedObjectContext在多线程中不安全
  • 若是想要多线程访问CoreData的话,最好的方法是一个线程一个NSManagedObjectContext
  • 每一个NSManagedObjectContext对象实例均可以使用同一个NSPersistentStoreCoordinator实例,这是由于NSManagedObjectContext会在便用NSPersistentStoreCoordinator前上锁

Core Data数据迁移

博客地址: http://blog.csdn.net/jasonblog/article/details/17842535

FMDB的使用和对多张表的处理

博客地址: http://blog.csdn.net/wscqqlucy/article/details/8464398

说说数据库的左链接和右链接的区别

  • 数据库左链接和右链接的区别:主表不同经过左链接和右链接,最小条数为3(记录条数较小的记录数),最大条数为12(3×4)

  • 技术博客的地址 : http://www.2cto.com/database/201407/317367.html

iOS 的沙盒目录结构是怎样的? App Bundle 里面都有什么?

  1. 沙盒结构

    • Application:存放程序源文件,上架前通过数字签名,上架后不可修改
    • Documents:经常使用目录,iCloud备份目录,存放数据,这里不能存缓存文件,不然上架不被经过
    • Library
      • Caches:存放体积大又不须要备份的数据,SDWebImage缓存路径就是这个
      • Preference:设置目录,iCloud会备份设置信息
    • tmp:存放临时文件,不会被备份,并且这个文件下的数据有可能随时被清除的可能
  2. App Bundle 里面有什么

    • Info.plist:此文件包含了应用程序的配置信息.系统依赖此文件以获取应用程序的相关信息
    • 可执行文件:此文件包含应用程序的入口和经过静态链接到应用程序target的代码
    • 资源文件:图片,声音文件一类的
    • 其余:能够嵌入定制的数据资源

你会如何存储用户的一些敏感信息,如登陆的 token

使用keychain来存储,也就是钥匙串,使用keychain须要导入Security框架

自定义一个keychain的类
#import <Security/Security.h> @implementation YCKKeyChain +(NSMutableDictionary *)getKeychainQuery:(NSString *)service { return [NSMutableDictionary dictionaryWithObjectsAndKeys: (__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass, service, (__bridge_transfer id)kSecAttrService, service, (__bridge_transfer id)kSecAttrAccount, (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock, (__bridge_transfer id)kSecAttrAccessible, nil]; } +(void)save:(NSString *)service data:(id)data { // 得到搜索字典 NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; // 添加新的删除旧的 SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery); // 添加新的对象到字符串 [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData]; // 查询钥匙串 SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL); } +(id)load:(NSString *)service { id ret = nil; NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; // 配置搜索设置 [keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge_transfer id)kSecReturnData]; [keychainQuery setObject:(__bridge_transfer id)kSecMatchLimitOne forKey: (__bridge_transfer id)kSecMatchLimit]; CFDataRef keyData = NULL; if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) { @try { ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)keyData]; } @catch (NSException *e) { NSLog(@"Unarchive of %@ failed: %@", service, e); } @finally { } } return ret; } +(void)delete:(NSString *)service { NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery); }

在别的类实现存储,加载,删除敏感信息方法
// 用来标识这个钥匙串
static NSString const KEY_IN_KEYCHAIN = @"com.yck.app.allinfo";
// 用来标识密码
static NSString 
const KEY_PASSWORD = @"com.yck.app.password";

+(void)savePassWord:(NSString *)password { NSMutableDictionary *passwordDict = [NSMutableDictionary dictionary]; [passwordDict setObject:password forKey:KEY_PASSWORD]; [YCKKeyChain save:KEY_IN_KEYCHAIN data:passwordDict]; } +(id)readPassWord { NSMutableDictionary *passwordDict = (NSMutableDictionary *)[YCKKeyChain load:KEY_IN_KEYCHAIN]; return [passwordDict objectForKey:KEY_PASSWORD]; } +(void)deletePassWord { [YCKKeyChain delete:KEY_IN_KEYCHAIN]; }

使用 NSUserDefaults 时,如何处理布尔的默认值?(好比返回 NO,不知道是真的 NO 仍是没有设置过)

if([[NSUserDefaults standardUserDefaults] objectForKey:ID] == nil){ NSLog(@"没有设置"); }

MD5和Base64的区别是什么,各自使用场景是什么?

作过加密相关的功能的,几乎都会使用到MD5和Base64,它们二者在实际开发中是最经常使用的。
•    MD5:是一种不可逆的摘要算法,用于生成摘要,没法逆着破解获得原文。经常使用的是生成32位摘要,用于验证数据的有效性。好比,在网络请求接口中,经过将全部的参数生成摘要,客户端和服务端采用一样的规则生成摘要,这样能够防篡改。又如,下载文件时,经过生成文件的摘要,用于验证文件是否损坏。 • Base64:属于加密算法,是可逆的,通过encode后,能够decode获得原文。在开发中,有的公司上传图片采用的是将图片转换成base64字符串,再上传。在作加密相关的功能时,一般会将数据进行base64加密/解密。

plist文件是用来作什么的。通常用它来处理一些什么方面的问题。

  • plist是iOS系统中特有的文件格式。咱们经常使用的NSUserDefaults偏好设置实质上就是plist文件操做。plist文件是用来持久化存储数据的。
  • 咱们一般使用它来存储偏好设置,以及那些少许的、数组结构比较复杂的不适合存储数据库的数据。好比,咱们要存储全国城市名称和id,那么咱们要优先选择plist直接持久化存储,由于更简单。

当存储大块数据是怎么作?

  • 你有不少选择,好比:
  • 使用NSUerDefaults
  • 使用XML, JSON, 或者 plist
  • 使用NSCoding存档
  • 使用相似SQLite的本地SQL数据库
  • 使用 Core Data
  • NSUserDefaults的问题是什么?虽然它很nice也很便捷,可是它只适用于小数据,好比一些简单的布尔型的设置选项,再大点你就要考虑其它方式了
  • XML这种结构化档案呢?整体来讲,你须要读取整个文件到内存里去解析,这样是很不经济的。使用SAX又是一个很麻烦的事情。
  • NSCoding?不幸的是,它也须要读写文件,因此也有以上问题。
  • 在这种应用场景下,使用SQLite 或者 Core Data比较好。使用这些技术你用特定的查询语句就能只加载你须要的对象。在性能层面来说,SQLite和Core Data是很类似的。他们的不一样在于具体使用方法。Core Data表明一个对象的graph model,但SQLite就是一个DBMS。Apple在通常状况下建议使用Core Data,可是若是你有理由不使用它,那么就去使用更加底层的SQLite吧。若是你使用SQLite,你能够用FMDB(https://GitHub.com/ccgus/fmdb)这个库来简化SQLite的操做,这样你就不用花不少经历了解SQLite的C API了

怎么解决sqlite锁定的问题

1> 设置数据库锁定的处理函数 int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); 函数能够定义一个回调函数,当出现数据库忙时,sqlite会调用该函数 当回调函数为NULL时,清除busy handle,申请不到锁直接返回 回调函数的第二个函数会被传递为该由这次忙事件调用该函数的次数 回调函数返回非0,数据库会重试当前操做,返回0则当前操做返回SQLITE_BUSY 2> 设定锁定时的等待时间 int sqlite3_busy_timeout(sqlite3*, 60); 定义一个毫秒数,当未到达该毫秒数时,sqlite会sleep并重试当前操做 若是超过ms毫秒,仍然申请不到须要的锁,当前操做返回sqlite_BUSY 当ms<=0时,清除busy handle,申请不到锁直接返回

文章若有问题,请留言,我将及时更正。

相关文章
相关标签/搜索