iOS 开发数据持久化详细讲解以及使用场景代码示例

257 阅读3分钟

在 iOS 开发中,数据持久化是应用开发的核心需求之一。以下是 iOS 中常见的数据持久化方案、适用场景及 Objective-C/Swift 双语言代码示例:


一、UserDefaults

场景: 适合存储轻量级配置信息(如用户设置、标识位等)

// Objective-C
// 存数据
[[NSUserDefaults standardUserDefaults] setObject:@"value" forKey:@"key"];
[[NSUserDefaults standardUserDefaults] synchronize];

// 取数据
NSString *value = [[NSUserDefaults standardUserDefaults] stringForKey:@"key"];
// Swift
// 存数据
UserDefaults.standard.set("value", forKey: "key")
UserDefaults.standard.synchronize()

// 取数据
let value = UserDefaults.standard.string(forKey: "key")

二、文件存储(Plist/文本文件)

场景: 适合存储结构化数据(如配置表、离线缓存)

// Objective-C - 写入Plist
NSArray *data = @[@"A", @"B", @1];
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
[data writeToFile:[path stringByAppendingPathComponent:@"data.plist"] atomically:YES];

// 读取
NSArray *readData = [NSArray arrayWithContentsOfFile:path];
// Swift - 写入文本文件
let text = "Hello World"
if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
    let fileURL = dir.appendingPathComponent("file.txt")
    do {
        try text.write(to: fileURL, atomically: false, encoding: .utf8)
    } catch { /* 错误处理 */ }
}

三、归档(NSKeyedArchiver)

场景: 存储自定义对象数据(需实现 NSCoding 协议)

// Objective-C
// 自定义类实现NSCoding
@interface Person : NSObject <NSCoding>
@property (nonatomic, copy) NSString *name;
@end

@implementation Person
- (void)encodeWithCoder:(NSCoder *)coder {
    [coder encodeObject:_name forKey:@"name"];
}
- (instancetype)initWithCoder:(NSCoder *)coder {
    if (self = [super init]) {
        _name = [coder decodeObjectForKey:@"name"];
    }
    return self;
}
@end

// 归档/解档
Person *person = [Person new];
person.name = @"John";
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:person];
[NSKeyedUnarchiver unarchiveObjectWithData:data];
// Swift - 使用Codable协议(推荐)
struct Person: Codable {
    var name: String
}

let person = Person(name: "John")
let data = try PropertyListEncoder().encode(person)
try data.write(to: fileURL)

// 解码
let loadedData = try Data(contentsOf: fileURL)
let decodedPerson = try PropertyListDecoder().decode(Person.self, from: loadedData)

四、SQLite 数据库

场景: 需要复杂查询的关系型数据存储

原生 SQLite(需导入 libsqlite3.tbd)

// Objective-C
sqlite3 *db;
NSString *dbPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"mydb.sqlite"];

if (sqlite3_open(dbPath.UTF8String, &db) == SQLITE_OK) {
    const char *createTable = "CREATE TABLE IF NOT EXISTS Users (id INTEGER PRIMARY KEY, name TEXT)";
    sqlite3_exec(db, createTable, NULL, NULL, NULL);
    
    // 插入数据
    const char *insert = "INSERT INTO Users (name) VALUES (?)";
    sqlite3_stmt *stmt;
    if (sqlite3_prepare_v2(db, insert, -1, &stmt, NULL) == SQLITE_OK) {
        sqlite3_bind_text(stmt, 1, "John", -1, SQLITE_TRANSIENT);
        sqlite3_step(stmt);
    }
    sqlite3_finalize(stmt);
}
sqlite3_close(db);
// Swift - 使用FMDB第三方库(推荐)
let dbPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + "/mydb.sqlite"
let db = FMDatabase(path: dbPath)

if db.open() {
    do {
        try db.executeUpdate("CREATE TABLE IF NOT EXISTS Users (id INTEGER PRIMARY KEY, name TEXT)", values: nil)
        try db.executeUpdate("INSERT INTO Users (name) VALUES (?)", values: ["John"])
    } catch { print(error) }
    db.close()
}

五、Core Data

场景: 需要对象关系管理的中大型应用

// Objective-C
// 1. 创建NSManagedObject子类
@interface User : NSManagedObject
@property (nonatomic, copy) NSString *name;
@end

// 2. 插入数据
NSManagedObjectContext *context = [self persistentContainer].viewContext;
User *newUser = [NSEntityDescription insertNewObjectForEntityForName:@"User" inManagedObjectContext:context];
newUser.name = @"John";
[context save:nil];

// 3. 查询数据
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"User"];
NSArray<User*> *users = [context executeFetchRequest:request error:nil];
// Swift
// 1. 定义Core Data模型
class User: NSManagedObject {
    @NSManaged var name: String
}

// 2. 插入数据
guard let context = persistentContainer?.viewContext else { return }
let newUser = User(context: context)
newUser.name = "John"
try? context.save()

// 3. 查询数据
let request: NSFetchRequest<User> = User.fetchRequest()
let users = try? context.fetch(request)

六、Realm(第三方库)

场景: 需要高性能、易用性的移动端数据库

// Swift
// 定义模型
class Dog: Object {
    @Persisted var name = ""
}

// 写入数据
let realm = try! Realm()
try! realm.write {
    let dog = Dog()
    dog.name = "Rex"
    realm.add(dog)
}

// 查询
let dogs = realm.objects(Dog.self).filter("name == 'Rex'")

总结对比

方案优点缺点适用场景
UserDefaults简单快捷不适合大量数据存储用户偏好设置
文件存储直接操作文件无结构化查询能力配置文件/简单数据缓存
归档支持自定义对象性能较差少量对象存储
SQLite关系型查询能力强需要SQL知识复杂数据关系场景
Core Data对象关系管理学习曲线陡峭中大型应用数据管理
Realm高性能、API简洁增加应用体积移动端高性能需求

开发者应根据项目规模、数据复杂度及团队技术栈选择最适合的方案。对于新项目,推荐优先考虑 Core Data(Apple 生态整合)或 Realm(跨平台易用性)。