📱 iOS数据持久化
✨ 核心概念
数据持久化是指将内存中的数据以特定格式保存到持久存储介质(如硬盘)的过程,使得应用重启后数据依然可用。在iOS中,由于沙盒机制的限制,应用只能访问自己沙盒内的文件。
沙盒目录是每个iOS应用独有的文件系统空间,与其他应用隔离,保证了数据的安全性。主要目录包括:
- Documents: 存放用户数据,iTunes同步时会备份。
- Library/Caches : 存放缓存数据, iTunes同步时不会备份。适合存储体积较大、不需要备份的非重要数据,如网络缓存。
- Library/Preferences: 存放偏好设置文件(通常通过NSUserDefaults操作),iTunes同步时会备份。
- tmp : 存放临时文件,系统可能在应用未运行时清除此目录,iTunes同步时不会备份。
🔍 主要持久化方案对比
方案 | 适用场景 | 特点 | 注意事项 |
---|---|---|---|
属性列表 (Plist) | 存储少量结构化数据(如配置信息) | 支持NSArray, NSDictionary等类型,XML格式,易读写 | 不能存储自定义对象,数据量大了性能差 |
偏好设置 (NSUserDefaults) | 用户偏好设置(如音量、开关状态) | 键值对存储,使用简单,数据自动保存到plist文件 | 不要存储敏感数据,非即时写入(必要时调用synchronize ) |
归档 (NSKeyedArchiver) | 存储自定义对象 | 可将对象序列化为二进制数据,支持加密,安全性较好 | 需对象实现NSCoding 或NSSecureCoding 协议 |
SQLite & FMDB | 大量结构化数据,需要复杂查询 | SQLite轻量级,FMDB是它的OC封装,面向对象,多线程安全 | 需编写SQL语句(FMDB可简化),处理数据库升级逻辑 |
Core Data | 复杂数据模型,对象图管理 | ORM框架,管理对象生命周期,支持数据迁移、撤销重做 | 学习曲线较陡峭,需理解其堆栈(Context, Coordinator, Model) |
💡 如何选择持久化方案
选择哪种方案,就像为不同的物品挑选不同的收纳工具,需要根据你的数据特点 和业务需求来决定:
- 小量简单配置或用户设置 :如是否首次启动、用户名等,用 NSUserDefaults。
- 少量结构化数据 :如城市列表、银行名称等不常修改的数据,可用 Plist。
- 自定义对象 :如用户信息、游戏存档,需实现
NSCoding
协议,使用归档。 - 大量有规律的数据,需频繁增删改查 :如聊天记录、新闻列表,用数据库(SQLite/FMDB或Core Data) 。
- 若追求更轻量级和直接控制SQL,选FMDB。
- 若需管理复杂对象关系、希望与系统深度集成,选Core Data。
- 敏感信息 :如用户密码、令牌,使用Keychain(钥匙串),它是系统级加密存储,应用删除后数据仍可保留。
🎯 常见面试问题与回答思路
-
iOS中主要有哪几种数据持久化方案?
- 思路:列出上述5种核心方案,并简要说明每种最适用的场景,展示你全面的了解。
-
NSUserDefaults 和 Keychain 有什么区别?
- 思路 :NSUserDefaults 用于存储非敏感的普通偏好设置,存储在沙盒的plist文件中。Keychain用于存储敏感信息,如密码、证书,提供加密保护,存储于系统级别,应用删除后数据仍存在(常用于存用户唯一标识)。
-
Core Data 和 SQLite 有什么区别?
- 思路 :Core Data 是一个对象图管理 和持久化框架,并非数据库。它可将对象保存到SQLite、XML等多种存储中。它提供高级功能如数据迁移、关系管理、撤销重做。SQLite 是一个轻量级的关系型数据库,通过SQL操作数据。Core Data在底层可以使用SQLite作为存储后端。
-
如何保证 Core Data 的多线程安全?
- 思路 :强调私有队列上下文 (Private Queue Context)的重要性。告知每个线程应使用独立的NSManagedObjectContext,并通过NSManagedObjectID在不同线程间传递对象引用。核心是避免多个线程共享同一个Context或ManagedObject。
-
什么是归档?如何实现一个自定义对象的归档?
- 思路 :归档是一种对象序列化机制,可将对象及其属性关系转换为二进制数据流(NSData)进行存储或传输。
- 实现步骤 :
- 让自定义类遵守
NSCoding
或NSSecureCoding
协议。 - 实现协议中的两个方法:
encode(with:)
: 在此方法中将对象的每个属性进行编码(encodeObject(_:forKey:)
等)。init(coder:)
: 在此方法中解码(decodeObject(forKey:)
等)并初始化对象的每个属性。
- 使用
NSKeyedArchiver
的archiveRootObject(_:toFile:)
方法归档。 - 使用
NSKeyedUnarchiver
的unarchiveObject(withFile:)
方法解档。
- 让自定义类遵守
-
沙盒中各个目录的作用是什么?应用上架时需要注意什么?
- 思路 :清晰说明Documents、Caches、Preferences、tmp目录的区别(如上文所述)。特别要注意,如果把缓存文件或临时文件放在Documents目录,可能会导致应用上架审核被拒,因为iTunes会同步备份Documents目录,而苹果要求此目录仅存储用户产生的重要数据。
🚀 面试进阶提示
- 结合项目经验:当被问到持久化时,最好能结合你项目中的实际使用场景。例如:"在我的上一个项目中,我使用Core Data来管理用户的收藏列表,因为它能很好地处理对象之间的关系和变化跟踪。"
- 了解底层原理:如果你能简要说明FMDB如何封装SQLite的C API,或Core Data的堆栈结构(Persistent Store Coordinator, Managed Object Model, Managed Object Context),会大大加分。
- 提及性能优化 :对于数据库操作,可以提及通过事务(Transaction) 来批量处理数据插入或更新,显著提升性能。
- 强调安全性:如果谈到敏感信息存储,一定要主动提到Keychain,这体现了你的安全意识。