我有一个定期运行的函数sync
,用于同步所有未同步的Realm模型(我在我的应用程序内部使用此sync
标志,只是为了检查我是否已处理模型或不是)。
我使用NSLock作为保护,因为sync
可能同时运行多次。
我遇到的问题是,有时会多次处理相同的模型。 我想知道我的代码中是否存在任何问题,以及如何解决它(我认为可能是因为realm.io可能是异步的)。
@property (strong, nonatomic) NSLock *lock;
- (void)sync
{
if (![self.lock tryLock]) return;
RLMResults *models = [Model objectsWhere:@"sync = 0"];
for (Model *model in models) {
[realm beginWriteTransaction];
model.sync = 1; // 1 step - Required to run the function.
[realm commitWriteTransaction];
[self myFunc]; // 2 step.
[self.lock unlock];
}
- (void)myFunc
{
NSLog(@"Updating view controller."):
}
答案 0 :(得分:2)
首先,如果您不需要将资源sync
永久保存在数据库中,您也可以将其添加到ignoredProperties
,然后您就不需要了一个写交易。
如果你有充分的理由将它存储在那里,你也可以使用write事务作为隐式锁定机制。
我们建议Realm支持将写入事务分组到大批量而不是大量小事务。这是因为我们的MVCC需要保留所有仍然被线程访问的版本,但尚未更新。
事先我解释说sync方法实际上做了一些工作,而不仅仅是切换sync
标志,而myFunc
正在用新数据更新视图控制器。如果sync
方法可以同时运行多次,则必须从另一个线程异步调用/运行它,因为主队列不是并发的。虽然myFunc
必须在主线程上运行,因为您只能从那里更新UI。这排除了它在这两种方法之间共享相同的Realm实例,因为访问器不是线程安全的。如果从同步方法中的大批量写入事务中的另一个线程的Realm实例触发UI更新,则模型更新尚未可见。因此,您还需要批量处理UI更新。
- (void)sync {
if (realm.inWriteTransaction) {
return;
}
[realm beginWriteTransaction];
RLMResults *models = [Model objectsWhere:@"sync = 0"];
NSArray *modelIds = [models valueForKey:@"primaryKey"];
for (Model *model in models) {
model.sync = 1; // 1st step.
// More expensive background work happens here?
}
[realm commitWriteTransaction];
// Asynchronous batched 2nd step.
dispatch_async(dispatch_get_main_queue(), ^{
[self myFuncWithUpdatedModelIds:modelIds];
});
}