I use Realm in my recent project - and I'm struggling to find an elegant solution to the problem that I have. To maintain responsiveness of the user interface, I try to act in most operations instantly. The entire user interface is disconnected from RLMResults, so in order to act something, I need to change the objects in Realm.
The fact is that these seemingly instant changes (I think the preference in the Twitter application) may fail, and I must undo the changes that I made if this happens.
I use ReactiveCocoa throughout the application, so continuing the explanation with my preferred example, I assume that for this I need something like the following:
- (RACSignal *)favoriteTweet:(Tweet *)tweet {
RACSignal *favoriteOnDatabase = [RACSignal createSignal:^RACDisposable *(id <RACSubscriber> *subscriber) {
[self.realm beginWriteTransaction];
tweet.favorited = YES;
[self.realm commitWriteTransaction];
[subscriber sendNext: tweet];
[subscriber sendCompleted];
return nil;
}];
RACSignal *syncChangesToAPI = [[[self.apiClient favoriteTweet:tweet] ignoreValues]
onError:^(NSError *error) {
[self.realm beginWriteTransaction];
[self.realm commitWriteTransaction];
}]
catch:^RACSignal *(NSError *error) {
return [RACSignal createSignal:^RACDisposable *(id <RACSubscriber> subscriber) {
[subscriber sendNext: tweet];
[subscriber sendError: error];
return nil;
}];
}];
return [favoriteOnDatabase concat: syncChangesToAPI];
}
:
Favorited tweet - [Error in API request] -> Unfavorited tweet -> Error
Realm AFAIK, , , , , favoriteOnDatabase, Realm, - , .
, , , , - , . ( ?)
- (RACSignal *)autoRollbackSyncSignalWithObject:(RLMObject *)object
apiSignal:(RACSignal *)apiSignal
changeBlock:(DataManagerAutoRollbackSyncSignalChangeBlock)changeBlock {
RLMObject *originalObject = [object two_shallowCopy];
__block RLMObject *modifiedObject = object;
RACSignal *localChange = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[self.realm beginWriteTransaction];
changeBlock(modifiedObject);
[self.realm commitWriteTransaction];
[subscriber sendNext:modifiedObject];
[subscriber sendCompleted];
return nil;
}];
RACSignal *syncOperation = [[[apiSignal ignoreValues] doError:^(NSError *error) {
[self.realm beginWriteTransaction];
if (object.invalidated) {
modifiedObject = originalObject;
[self.realm addObject:modifiedObject];
} else if (!originalObject && modifiedObject) {
[self.realm deleteObject:modifiedObject];
} else {
[modifiedObject two_mergePropertiesFromObject:originalObject];
}
[self.realm commitWriteTransaction];
}] catch:^RACSignal *(NSError *error) {
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:modifiedObject];
[subscriber sendError:error];
return nil;
}];
}];
return [localChange concat:syncOperation];
}
? - , ?
!