---
title: ReactiveCocoa and Core Data Concurrency
teaser: Make using Core Data with ReactiveCocoa suck less.
tags: ios
author: Keith Smiley
published_on: 2015-02-20
---

Recently, as discussed on some [episodes](http://buildphase.fm/70) of
[Build Phase](http://buildphase.fm/71), the iOS developers in San
Francisco have finally gotten on the
[ReactiveCocoa](https://github.com/ReactiveCocoa/ReactiveCocoa)
bandwagon. While there are a lot of great resources to help you get up
and running with the functional reactive programming paradigm, one thing
that I didn't feel like is well covered anywhere is using ReactiveCocoa
in tandem with Core Data's [concurrency
model](https://thoughtbot.com/blog/core-data). Ideally, we would use a
private queue context to perform some intense work, then we would save
that context and its changes would be merged into the main queue context
via the
[`NSManagedObjectContextDidSaveNotification`](https://developer.apple.com/library/ios/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectContext_Class/index.html#//apple_ref/c/data/NSManagedObjectContextDidSaveNotification)
notification. Following this pattern with ReactiveCocoa can produce some
ugly code if you want to continue to transform the returned values.
Let's look at an example where we have a `fetchObjects` signal:

```objc
[[[[APIClient fetchObjects] map:^NSArray *(NSArray *objects) {
    __block NSArray *objects;
    [backgroundContext performBlockAndWait:^{
        pullRequests = [self createManagedObjectsFromJSON:objects
                                                inContext:backgroundContext];
    }];

    return objects;
}] map:^NSArray *(NSArray *objects) {
    __block NSArray *importantObjects;
    [backgroundContext performBlockAndWait:^{
        importantObjects = [objects filteredArrayUsingPredicate:
                            [self importantPredicate]];
    }];

    return importantObjects;
}] filter:^BOOL(NSArray *objects) {
    return objects.count > 0;
}];
```

The problem with this code, besides `performBlockAndWait:` possibly
creating a deadlock, is Core Data doesn't fit very well with
ReactiveCocoa's approach to signal flow. One way we can solve this is by
executing our signals on a custom
[`RACScheduler`](https://github.com/ReactiveCocoa/ReactiveCocoa/blob/54098f8b457d5fa6b2a285d790c2c07c099b98f5/ReactiveCocoa/RACScheduler.h).
This allows us to execute blocks on the private queue created by our
`NSManagedObjectContext`. Let's look at the subclass we need for this.

```objc
@interface CoreDataScheduler ()

@property (nonatomic) NSManagedObjectContext *context;

@end

@implementation CoreDataScheduler

- (instancetype)initWithContext:(NSManagedObjectContext *)context
{
    self = [super init];
    if (!self) return nil;

    self.context = context;

    return self;
}

- (RACDisposable *)schedule:(void (^)(void))block
{
    NSParameterAssert(block);

    RACDisposable *disposable = [RACDisposable new];

    [self.context performBlock:^{
        if (disposable.disposed) {
            return;
        }

        block();
    }];

    return disposable;
}

@end
```

First we'll initialize our scheduler with a context. Then, in our
`schedule:` method, we'll perform our work in our context's
`performBlock:` method so it happens on the correct queue. Using this
new scheduler we can clean up our original example.

```objc
CoreDataScheduler *scheduler = [[CoreDataScheduler alloc] initWithContext:context];
[[[[[[APIClient fetchObjects] deliverOn:scheduler] map:^NSArray *(NSArray *objects) {
    return [self createManagedObjectsFromJSON:objects inContext:context];
}] deliverOn:scheduler] map:^NSArray *(NSArray *objects) {
    return [objects filteredArrayUsingPredicate:[self importantPredicate]];
}] filter:^BOOL(NSArray *objects) {
    return objects.count > 0;
}];
```

Using `deliverOn:`, we can make our ReactiveCocoa blocks happen through
our custom scheduler. This way we don't have to worry about using
`performBlockAndWait:` with Core Data and we end up with cleaner looking
code. While using ReactiveCocoa with Apple's frameworks we have found
many places where modifications like this can greatly decrease the
friction between programming paradigms.

## More on learning ReactiveCocoa

- [Official ReactiveCocoa documentation]
- [ReactiveCocoa and MVVM, an Introduction]
- [Getting Started with ReactiveCocoa]
- [The introduction to Reactive Programming you've been missing][frp]
- [ReactiveCocoa Tutorial]

[Official ReactiveCocoa documentation]: https://github.com/ReactiveCocoa/ReactiveCocoa/tree/master/Documentation
[ReactiveCocoa and MVVM, an Introduction]: http://www.sprynthesis.com/2014/12/06/reactivecocoa-mvvm-introduction/
[Getting Started with ReactiveCocoa]: http://www.teehanlax.com/blog/getting-started-with-reactivecocoa/
[frp]: https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
[ReactiveCocoa Tutorial]: http://www.raywenderlich.com/62699/reactivecocoa-tutorial-pt1
