
realm官网传送门
Object-C版本具体接口
个人推荐这篇Realm数据库 从入门到“放弃”
看完请记住这两点:
- 非线程安全的,读写必须和realm对象在同一进程。跨线程访问数据库,Realm对象一定需要新建一个。
- transactionWithBlock 已经处于一个写的事务中,事务之间不能嵌套
RLMRealm *realm = [RLMRealm defaultRealm];
[realm transactionWithBlock:^{
//block里面不能再有事务操作了,否则会报错
[Person createInRealm:realm withValue:@[@"John", @[@[@"Fido", @1]]]];
[Person createInRealm:realm withValue:@[@"Mary", @[@[@"Rex", @2]]]];
}];
OK,看到这里你可以放弃了
皮一下也挺开心的。哈哈哈
参考官方demo,开始动手撸代码吧!
realm的基本使用
模型
RLM_ARRAY_TYPE(Dog) //RLM_ARRAY_TYPE宏创建了一个协议,从而允许RLMArray<Dog> *dogs语法的使用
@interface Person : RLMObject
@property NSString *name;
@property RLMArray <Dog> *dogs;
@end
操作
#pragma mark - 创建数据库
-(void)creatData{
NSLog(@"创建数据库");
[[NSFileManager defaultManager] removeItemAtURL:[RLMRealmConfiguration defaultConfiguration].fileURL error:nil];
}
#pragma mark - 创建模型对象、并赋值
-(void)creatModelObject{
// Create a standalone object
mydog = [[Dog alloc] init];
// Set & read properties
mydog.name = @"创建模型对象、并赋值 Rex";
mydog.age = 9;
NSLog(@"创建模型对象、并赋值 mydog=%@",mydog);
}
#pragma mark - 保存数据
-(void)addData{
if (!mydog) {
NSLog(@"请创建模型对象、并赋值");
return;
}
// Realms are used to group data together
RLMRealm *realm = [RLMRealm defaultRealm]; // Create realm pointing to default file
// Save your object
[realm beginWriteTransaction];
[realm addObject:mydog];
[realm commitWriteTransaction];
NSLog(@"保存数据");
}
#pragma mark - 查询数据
-(void)queryData{
NSLog(@"查询数据");
// Query
RLMRealm *realm = [RLMRealm defaultRealm];
RLMResults *results = [Dog objectsInRealm:realm where:@"name contains 'x'"];
// Queries are chainable!
RLMResults *results2 = [results objectsWhere:@"age > 8"];
NSLog(@"Number of dogs: %li", (unsigned long)results2.count);
// Link objects
Person *person = [[Person alloc] init];
person.name = @"Tim";
[person.dogs addObject:mydog];
[realm beginWriteTransaction];
[realm addObject:person];
[realm commitWriteTransaction];
// Multi-threading
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@autoreleasepool {
RLMRealm *otherRealm = [RLMRealm defaultRealm];
RLMResults *otherResults = [Dog objectsInRealm:otherRealm where:@"name contains 'Rex'"];
NSLog(@"Number of dogs: %li", (unsigned long)otherResults.count);
}
});
}
输出
2019-08-22 11:05:38.228017+0800 rmMigrations-OC[7537:133107] 创建数据库
2019-08-22 11:05:39.677837+0800 rmMigrations-OC[7537:133107] 创建模型对象、并赋值 mydog=Dog {
name = 创建模型对象、并赋值 Rex;
age = 9;
}
2019-08-22 11:05:41.362775+0800 rmMigrations-OC[7537:133107] 保存数据
2019-08-22 11:05:42.413749+0800 rmMigrations-OC[7537:133107] 查询数据
2019-08-22 11:05:42.426567+0800 rmMigrations-OC[7537:133107] Number of dogs: 1
2019-08-22 11:05:42.430851+0800 rmMigrations-OC[7537:135529] Number of dogs: 1

做一下修改,创建数据库的配置写在AppDelegate
#pragma mark - 创建数据库的配置
- (void)creatrRealmDataBaseWithName:(NSString *)databaseName
{
NSArray *docPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [docPath objectAtIndex:0];
NSString *filePath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.realm",databaseName]];//添加.realm便于识别
NSLog(@"realm数据库目录 = %@",filePath);
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
config.fileURL = [NSURL URLWithString:filePath];
//config.objectClasses = @[MyClass.class, MyOtherClass.class];//限制某些模型进行数据迁移
config.readOnly = NO;
int currentVersion = 1.0;
config.schemaVersion = currentVersion;
config.migrationBlock = ^(RLMMigration *migration , uint64_t oldSchemaVersion) {
// 这里是设置数据迁移的block
if (oldSchemaVersion < currentVersion) {
NSLog(@"migrations");
}
};
[RLMRealmConfiguration setDefaultConfiguration:config];
}
打开数据库所在目录,然而没有发现有relam数据库,只有 wegood.note的标记
➜ Documents cd /Users/samtake/Library/Developer/CoreSimulator/Devices/5F2978C1-3DEF-4BFF-92B3-9955E7A4AA53/data/Containers/Data/Application/9008C4E0-827B-4ED5-9040-B026739FB23F/Documents/
➜ Documents ls
default.realm.management wegood.management
default.realm.note wegood.note
➜ Documents open .
➜ Documents
这时需要存入数据才会生成wegood.realm

反向链接
加密
model字段的自加操作
数据更新通知
关于通知先看下源码里面对涉及的函数说明
/**
Registers a block to be called each time the results collection changes.
The block will be asynchronously called with the initial results collection,
and then called again after each write transaction which changes either any
of the objects in the results, or which objects are in the results.
The `change` parameter will be `nil` the first time the block is called.
For each call after that, it will contain information about
which rows in the results collection were added, removed or modified. If a
write transaction did not modify any objects in the results collection,
the block is not called at all. See the `RLMCollectionChange` documentation for
information on how the changes are reported and an example of updating a
`UITableView`.
If an error occurs the block will be called with `nil` for the results
parameter and a non-`nil` error. Currently the only errors that can occur are
when opening the Realm on the background worker thread.
At the time when the block is called, the `RLMResults` object will be fully
evaluated and up-to-date, and as long as you do not perform a write transaction
on the same thread or explicitly call `-[RLMRealm refresh]`, accessing it will
never perform blocking work.
Notifications are delivered via the standard run loop, and so can't be
delivered while the run loop is blocked by other activity. When
notifications can't be delivered instantly, multiple notifications may be
coalesced into a single notification. This can include the notification
with the initial results. For example, the following code performs a write
transaction immediately after adding the notification block, so there is no
opportunity for the initial notification to be delivered first. As a
result, the initial notification will reflect the state of the Realm after
the write transaction.
RLMResults<Dog *> *results = [Dog allObjects];
NSLog(@"dogs.count: %zu", dogs.count); // => 0
self.token = [results addNotificationBlock:^(RLMResults *dogs,
RLMCollectionChange *changes,
NSError *error) {
// Only fired once for the example
NSLog(@"dogs.count: %zu", dogs.count); // => 1
}];
[realm transactionWithBlock:^{
Dog *dog = [[Dog alloc] init];
dog.name = @"Rex";
[realm addObject:dog];
}];
// end of run loop execution context
You must retain the returned token for as long as you want updates to continue
to be sent to the block. To stop receiving updates, call `-invalidate` on the token.
@warning This method cannot be called during a write transaction, or when the
containing Realm is read-only.
@param block The block to be called whenever a change occurs.
@return A token which must be held for as long as you want updates to be delivered.
*/
- (RLMNotificationToken *)addNotificationBlock:(void (^)(RLMResults<RLMObjectType> *__nullable results,
RLMCollectionChange *__nullable change,
NSError *__nullable error))block __attribute__((warn_unused_result));
addNotificationBlock函数写在RLMResults
类里的,
- 注意⚠️一下:在写入事务期间,或者当包含realm时是只读的(这个我的理解是嵌套realm,但这样子不是会崩溃吗??)
- 参数是:每次发生更改时都会调用里面的block
- 返回一个RLMNotificationToken类型的token,只要您希望传递更新,它就必须保留。所以一般都是通过strong来声明。
self.array = [[TableViewModel allObjects]sortedResultsUsingKeyPath:@"name" ascending:YES];
/**
Whether the descriptor sorts in ascending or descending order.
*/
@property (nonatomic, readonly) BOOL ascending;
根据描述符是按升序还是降序排序
- YES 升序
- NO 降序
数据迁移升级
数据迁移官方demo一共列出了出了三种类型
- 合并字段的迁移
- 增加新字段的迁移
- 原字段重命名的迁移
RLMMigrationBlock migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) {
if (oldSchemaVersion < 1) {//合并字段的迁移
[migration enumerateObjects:Person.className block:^(RLMObject *oldObject, RLMObject *newObject) {
if (oldSchemaVersion < 1) {
// combine name fields into a single field
newObject[@"fullName"] = [NSString stringWithFormat:@"%@ %@", oldObject[@"firstName"], oldObject[@"lastName"]];
}
}];
}
if (oldSchemaVersion < 2) {//增加新字段的迁移
NSLog(@"[RLMRealmConfiguration defaultConfiguration].fileURL=%@",[RLMRealmConfiguration defaultConfiguration].fileURL);
[migration enumerateObjects:Person.className block:^(RLMObject *oldObject, RLMObject *newObject) {
// give JP a dog
if ([newObject[@"fullName"] isEqualToString:@"JP McDonald"]) {
Pet *jpsDog = [[Pet alloc] initWithValue:@[@"Jimbo", @(AnimalTypeDog)]];
[newObject[@"pets"] addObject:jpsDog];
}
}];
}
if (oldSchemaVersion < 3) {//原字段重命名的迁移
NSLog(@"[RLMRealmConfiguration defaultConfiguration].fileURL=%@",[RLMRealmConfiguration defaultConfiguration].fileURL);
[migration enumerateObjects:Pet.className block:^(RLMObject *oldObject, RLMObject *newObject) {
// convert type string to type enum if we have outdated Pet object
if (oldObject && oldObject.objectSchema[@"type"].type == RLMPropertyTypeString) {
newObject[@"type"] = @([Pet animalTypeForString:oldObject[@"type"]]);
}
}];
}
NSLog(@"Migration complete.");
};
增加新字段的迁移实操
v0版本
//v0
@property NSString *name;
@property NSInteger age;
//v0
- (void)creatrRealmDataBase{
NSArray *docPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [docPath objectAtIndex:0];
NSString *filePath = [path stringByAppendingPathComponent:@"wegood_v0.realm"];//添加.realm便于识别
NSLog(@"realm数据库目录 = %@",filePath);
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
config.fileURL = [NSURL URLWithString:filePath];
NSLog(@"schemaVersion=%llu",config.schemaVersion);
[RLMRealmConfiguration setDefaultConfiguration:config];
}

v1版本
//v1
@property NSString *oneWorld;
@property NSString *name;
@property NSInteger age;
//v1
- (void)creatrRealmDataBase{
NSArray *docPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [docPath objectAtIndex:0];
//旧数据库地址
NSString *filePathOld = [path stringByAppendingPathComponent:@"wegood_v0.realm"];//添加.realm便于识别
NSLog(@"filePathOld = %@",filePathOld);
NSURL *oldURL = [NSURL URLWithString:filePathOld];
//新数据库地址
NSString *filePathNew = [path stringByAppendingPathComponent:@"wegood_v1.realm"];
NSLog(@"filePathNew = %@",filePathNew);
NSURL *newURL = [NSURL URLWithString:filePathNew];
[[NSFileManager defaultManager] removeItemAtURL:oldURL error:nil];
[[NSFileManager defaultManager] copyItemAtURL:oldURL toURL:newURL error:nil];
RLMMigrationBlock migrationBlock = ^(RLMMigration *migration , uint64_t oldSchemaVersion) {
// 这里是设置数据迁移的block
if (oldSchemaVersion == 1) {
/*if(currentVersion==1.0){*/
NSLog(@"migrations");
[migration enumerateObjects:Dog.className block:^(RLMObject *oldObject, RLMObject *newObject) {
[newObject[@"oneWorld"] addObject:@"数据迁移的默认值"];
}];
}
};
RLMRealmConfiguration *configuration = [RLMRealmConfiguration defaultConfiguration];
configuration.schemaVersion = 1;
configuration.migrationBlock = migrationBlock;
[RLMRealmConfiguration setDefaultConfiguration:configuration];
[RLMRealm defaultRealm];
// set schemave versions and migration blocks form Realms at each path
RLMRealmConfiguration *realmv1Configuration = [configuration copy];
realmv1Configuration.fileURL = newURL;
// manully migration v1Path, v2Path is migrated implicitly on access
[RLMRealm performMigrationForConfiguration:realmv1Configuration error:nil];
}

demo链接https://github.com/samtake/rmMigrations-OC
后续再更...
网友评论