10

我正在构建的客户端正在使用带有Octokit的Reactive Cocoa ,到目前为止它进展顺利。但是现在我正处于想要获取存储库集合的地步,并且无法用“RAC方式”来解决这个问题

// fire this when an authenticated client is set
[[RACAbleWithStart([GHDataStore sharedStore], client) 
  filter:^BOOL (OCTClient *client) {
      return client != nil && client.authenticated;
  }]
 subscribeNext:^(OCTClient *client) {
     [[[client fetchUserRepositories] deliverOn:RACScheduler.mainThreadScheduler]
      subscribeNext:^(OCTRepository *fetchedRepo) {
          NSLog(@" Received new repo: %@",fetchedRepo.name);
      }
      error:^(NSError *error) {
          NSLog(@"Error fetching repos: %@",error.localizedDescription);
      }];
 } completed:^{
     NSLog(@"Completed fetching repos");
 }];

我最初假设它-subscribeNext:会传递一个NSArray,但现在明白它会发送消息每个返回的“下一个”对象,在这种情况下是一个OCTRepository.

现在我可以做这样的事情:

NSMutableArray *repos = [NSMutableArray array];
// most of that code above
subscribeNext:^(OCTRepository *fetchedRepo) {
    [repos addObject:fetchedRepo];
}
// the rest of the code above

当然,这行得通,但它似乎没有遵循 RAC 启用的功能原则。我真的很想在这里遵守约定。非常感谢 RAC/Octokit 的任何功能!

4

2 回答 2

15

这在很大程度上取决于您以后要对存储库做什么。拥有所有存储库后,您似乎想要做某事,因此我将设置一个示例来执行此操作。

// Watch for the client to change
RAC(self.repositories) = [[[[[RACAbleWithStart([GHDataStore sharedStore], client) 
    // Ignore clients that aren't authenticated
    filter:^ BOOL (OCTClient *client) {
        return client != nil && client.authenticated;
    }]
    // For each client, execute the block. Returns a signal that sends a signal
    // to fetch the user repositories whenever a new client comes in. A signal of
    // of signals is often used to do some work in response to some other work.
    // Often times, you'd want to use `-flattenMap:`, but we're using `-map:` with
    // `-switchToLatest` so the resultant signal will only send repositories for
    // the most recent client.
    map:^(OCTClient *client) {
        // -collect will send a single value--an NSArray with all of the values
        // that were send on the original signal.
        return [[client fetchUserRepositories] collect];
    }]
    // Switch to the latest signal that was returned from the map block.
    switchToLatest]
    // Execute a block when an error occurs, but don't alter the values sent on
    // the original signal.
    doError:^(NSError *error) {
        NSLog(@"Error fetching repos: %@",error.localizedDescription);
    }]
    deliverOn:RACScheduler.mainThreadScheduler];

self.repositories每当从客户端更新存储库时,Now将更改(并触发 KVO 通知)。

有几点需要注意:

  1. 最好尽可能避免subscribeNext:。使用它超出了功能范式(就像doNext:和一样doError:,但它们有时也是有用的工具)。一般来说,您想考虑如何将信号转换为您想要的东西。

  2. 如果您想将一个或多个工作链接在一起,您通常需要使用flattenMap:. 更一般地说,你想开始考虑信号的信号——发送代表其他工作的其他信号的信号。

  3. 您通常希望尽可能长时间地等待将工作移回主线程。

  4. 在思考一个问题时,有时从写下每个单独的信号开始思考 a) 你拥有什么,b) 你想要什么,以及 c) 如何从一个到另一个是很有价值的。

编辑:更新以解决下面的@JustinSpahrSummers 评论。

于 2013-06-24T18:02:08.113 回答
2

有一个 -collect 运算符应该完全符合您的要求。

// Collect all receiver's `next`s into a NSArray. nil values will be converted
// to NSNull.
//
// This corresponds to the `ToArray` method in Rx.
//
// Returns a signal which sends a single NSArray when the receiver completes
// successfully.
- (RACSignal *)collect;
于 2013-06-24T17:53:11.503 回答