Using ReactiveCocoa, Kiwi, and Cocoapods together, getting "is not a tuple" exception

825 Views Asked by At

I'm trying to get a new project set up using ReactiveCocoa and Kiwi for testing, using CocoaPods for dependency management.

I have a first test set up for a typical login screen, where the login button isn't enabled until the user has input something for the username and password. Just a simpler version of some of the example code:

- (void)viewDidLoad
{
    [super viewDidLoad];
    RAC(self.loginButton, enabled) = [RACSignal combineLatest:@[self.userNameField.rac_textSignal,
                                                            self.passwordField.rac_textSignal]
                                                       reduce:^(NSString *username, NSString *password) {
        return @(username.length > 0 && password.length > 0);
    }];
}

The problem is that when I run my tests, I get the following error:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Value from stream <RACDynamicSignal: 0xe3735a0> name: +combineLatest: (
    "<RACDynamicSignal: 0xe368c50> name: <UITextField: 0xe3707a0> -rac_textSignal",
    "<RACDynamicSignal: 0xe372d80> name: <UITextField: 0xe36aef0> -rac_textSignal"
) is not a tuple: <RACTuple: 0xe377a40> (
    "",
    ""
)'

Of course, it is a RACTuple, so that's just confusing.

My research turned up the following issue on ReactiveCocoa:

https://github.com/ReactiveCocoa/ReactiveCocoa/issues/901

The diagnosis there is that ReactiveCocoa is getting linked in twice somehow. The person who had the issue there solved it by ditching CocoaPods. That doesn't seem right. Has anyone gotten this working?

For completeness, my Podfile is:

platform :ios, '6.0'

pod 'ReactiveCocoa'

target :test do
  link_with 'PollVaultTests'
  pod 'Kiwi/XCTest'
end
1

There are 1 best solutions below

1
On BEST ANSWER

Well, I get to answer my own question.

It turns out that when pods are listed at the "global" level in your Podfile, CocoaPods includes them in all targets.

The result in this case is that my main project links in CocoaPods - and so does my test target.

When my test target gets injected into my main project to run the tests - you get ReactiveCocoa linked in twice. So there are two classes named RACTuple floating around - and so when the ReactiveCocoa code internally checks to make sure its argument is a RACTuple, it checks against the wrong copy of the class and effectively has a false negative result.

The solution is to make sure that my test target in the Podfile is configured to link in only the test pods like so:

platform :ios, '6.0'

pod 'ReactiveCocoa'

target :test, :exclusive => true do
  link_with 'PollVaultTests'
  pod 'Kiwi/XCTest'
end

That :exclusive => true part is what tells Cocoapods to only include the Kiwi test framework in my test target. Problem solved!