接上篇。。。
4. 可空属性&默认值&忽略属性
默认情况下, 属性值可空, 如果强制要求某个属性非空, 可以使用如下方法:
遵循协议方法
+ (NSArray *)requiredProperties {
return @[@"name"];
}
特点:如果再次赋值为nil, 则会抛出异常错误
也可以设置默认值
+ (NSDictionary *)defaultPropertyValues {
return @{@"name": @""};
}
忽略属性:不想存储的某些属性,其实现方法为
+ (NSArray *)ignoredProperties
开发经验:
可以借助忽略属性&只读属性 打造计算属性, 完成集合以及UIImage对象的存储与获取
5. 通知
Realm 实例将会在每次写入事务提交后,给其他线程上的 Realm 实例发送通知
5.1. 获取 Realm 通知
token = [realm addNotificationBlock:^(NSString *notification, RLMRealm * realm) {
// 接收到更改通知, 需要做的事情
}];
5.2. 移除通知
[token stop];
注意:必须持有返回的token
6. Realm数据库
实现方案
不同的用户, 使用不同的数据库
+ (void)setDefaultRealmForUser:(NSString *)username { RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration]; // 使用默认的目录,但是使用用户名来替换默认的文件名 config.fileURL= [[[config.fileURL URLByDeletingLastPathComponent] URLByAppendingPathComponent:username] URLByAppendingPathExtension:@"realm"]]]; // 将这个配置应用到默认的 Realm 数据库当中 [RLMRealmConfiguration setDefaultConfiguration:config]; }
只读方式打开数据库
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration]; // 获取需要打包文件的 URL 路径 config.fileURL = [[NSBundle mainBundle] URLForResource:@"MyBundledData" withExtension:@"realm"]; // 以只读模式打开文件,因为应用数据包并不可写 config.readOnly = YES; // 通过配置打开 Realm 数据库 RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:nil]; // 从打包的 Realm 数据库中读取某些数据 RLMResults<Dog *> *dogs = [Dog objectsInRealm:realm where:@"age > 5"];
数据库文件删除
注意: 需要删除数据库文件以及辅助文件
代码实战:
NSFileManager *manager = [NSFileManager defaultManager]; RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration]; NSArray<NSURL *> *realmFileURLs = @[ config.fileURL, [config.fileURL URLByAppendingPathExtension:@"lock"], [config.fileURL URLByAppendingPathExtension:@"log_a"], [config.fileURL URLByAppendingPathExtension:@"log_b"], [config.fileURL URLByAppendingPathExtension:@"note"] ]; for (NSURL *URL in realmFileURLs) { NSError *error = nil; [manager removeItemAtURL:URL error:&error]; if (error) { // 处理错误 } }
7. 数据库迁移
适用于修改了数据模型的情况,这里分 数据结构迁移 以及 数据迁移 属性重命名 多版本增量式迁移 四个模块分别进行说明。
- 数据结构迁移
// 在 [AppDelegate didFinishLaunchingWithOptions:] 中进行配置 RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration]; // 设置新的架构版本。这个版本号必须高于之前所用的版本号(如果您之前从未设置过架构版本,那么这个版本号设置为 0) config.schemaVersion = 1; // 设置闭包,这个闭包将会在打开低于上面所设置版本号的 Realm 数据库的时候被自动调用 config.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) { // 目前我们还未进行数据迁移,因此 oldSchemaVersion == 0 if (oldSchemaVersion < 1) { // 什么都不要做!Realm 会自行检测新增和需要移除的属性,然后自动更新硬盘上的数据库架构 }; } // 告诉 Realm 为默认的 Realm 数据库使用这个新的配置对象 [RLMRealmConfiguration setDefaultConfiguration:config]; // 现在我们已经告诉了 Realm 如何处理架构的变化,打开文件之后将会自动执行迁移 [RLMRealm defaultRealm];
- 数据迁移
// enumerateObjects:block: 方法遍历了存储在 Realm 文件中的每一个“Person”对象 [migration enumerateObjects:Person.className block:^(RLMObject *oldObject, RLMObject *newObject) { // 将名字进行合并,存放在 fullName 域中 newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@", oldObject[@"firstName"], oldObject[@"lastName"]]; }];
- 属性重命名
[migration renamePropertyForClass:Person.className oldName:@"yearsSinceBirth" newName:版本0
- 多版本增量式迁移
假设有如下3个数据库版本:
版本0
// v0 @interface Person : RLMObject @property NSString *firstName; @property NSString *lastName; @property int age; @end 版本1 // v1 @interface Person : RLMObject @property NSString *fullName; // 新属性 @property int age; @end 版本2 // v2 @interface Person : RLMObject @property NSString *fullName; @property NSString *email; // 新属性 @property int age; @end
迁移核心代码
if (oldSchemaVersion < 1) { newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@", oldObject[@"firstName"], oldObject[@"lastName"]]; } // 只有当 Realm 数据库的架构版本为 0 的时候,才添加 “fullName” 属性 [migration enumerateObjects:Person.className block:^(RLMObject *oldObject, RLMObject *newObject) { if (oldSchemaVersion < 2) { newObject[@"email"] = @""; } }];