Cocoa touch 如何使用ReactiveCocoa实现承诺模式?

Cocoa touch 如何使用ReactiveCocoa实现承诺模式?,cocoa-touch,reactive-cocoa,Cocoa Touch,Reactive Cocoa,我是刚接触iOS开发的,来自于EmberJS的JS背景。我想将我的EmberJS应用程序移植到iOS应用程序。因此,我想在我的iOS应用程序中使用类似的结构。当EmberJS大量使用promises时,我在iOS上搜索了类似的东西,偶然发现了ReactiveCocoa在ReactiveCocoa的介绍中说,这个框架可以用来实现承诺。我尝试过,但它不能正常工作。我想从一个非常简单的例子开始: 发出异步网络请求(以填充UITableViewController)。从该方法返回承诺 订阅此承诺,并在

我是刚接触iOS开发的,来自于EmberJS的JS背景。我想将我的EmberJS应用程序移植到iOS应用程序。因此,我想在我的iOS应用程序中使用类似的结构。当EmberJS大量使用promises时,我在iOS上搜索了类似的东西,偶然发现了ReactiveCocoa在ReactiveCocoa的介绍中说,这个框架可以用来实现承诺。我尝试过,但它不能正常工作。我想从一个非常简单的例子开始:

  • 发出异步网络请求(以填充UITableViewController)。从该方法返回承诺
  • 订阅此承诺,并在完成后重新加载TableView
我想这样做,因为在成功加载数据之后,我必须执行一些操作我的方法基本有效,但我遇到以下问题:

  • 我的TableView不会在请求完成后立即重新加载。
  • 请求完成后,我立即在订阅中看到日志语句已完成。但是TableView保持空白
  • TableView在等待几秒钟后加载数据
  • 如果在看到日志输出后开始滚动TableView,TableView会突然被加载
我怀疑这可能是因为我正在后台线程中获取数据我认为承诺(
subscribebcompleted
)的解决也可能发生在后台线程中,Cocoa Touch可能不喜欢这样。
我说得对吗?但如果是这样,我该如何履行承诺

我希望你能帮助我开始使用ReactiveCocoa。Thx!:-)

更新: 我设法通过将to
reloadData
包装在
dispatch\u async(dispatch\u get\u main\u queue(),^{…
中来修复它,但我仍然不确定这是最好的方法还是ReactiveCocoa推荐的方法。因此我仍然渴望听到一些答案

//此方法希望使用承诺
-(无效)随后加载数据和性能{
RACSignal*signal=[self-fetchObjects];
[信号订阅完成:^{
NSLog(@“已输入订阅完成块信号!”);
NSLog(@“对象数:%i”,self.objects.count);
[self.tableView重载数据];
}];
}
//这个方法返回一个承诺。我省略了一些部分,但它基本上显示了我如何解决这个承诺。
-(RACSignal*)获取CurrentFormState的影片{
返回[RACSignal createSignal:^RACSignal*(id订户){
NSLog(@“RAC createSignal Block called”);
NSString*requestURL=@“…”;
NSURL*urlObj=[NSURL URLWithString:requestURL];
调度异步(调度获取全局队列(调度队列优先级默认为0)^{
NSData*data=[NSData dataWithContentsOfURL:urlObj];
如果(数据){
[self-performSelectorOnMainThread:@selector(fetchedData:)
withObject:data waitUntilDone:YES];
[用户发送完成];
}否则{
//尚未实现:处理错误案例
[用户发送完成];
}
});
//实际上我还不知道我应该在这里返回什么。从一个基本的例子中复制。
返回零;
}];
}

你说得对,这是一个线程问题。但是,你不需要降低到GCD级别

信号可以“传递”到另一个线程,该线程只调用那里的任何订阅回调:

- (void) loadDataAndPerformActionsAfterwards {
    [[[self
        fetchObjects]
        deliverOn:RACScheduler.mainThreadScheduler]
        subscribeCompleted:^{
            NSLog(@"Entered subscribeCompleted block signal!");
            NSLog(@"Number of objects: %i", self.objects.count);
            [self.tableView reloadData];
        }];
}

你是对的,这是线程的问题。但是,你不需要降低到GCD级别

信号可以“传递”到另一个线程,该线程只调用那里的任何订阅回调:

- (void) loadDataAndPerformActionsAfterwards {
    [[[self
        fetchObjects]
        deliverOn:RACScheduler.mainThreadScheduler]
        subscribeCompleted:^{
            NSLog(@"Entered subscribeCompleted block signal!");
            NSLog(@"Number of objects: %i", self.objects.count);
            [self.tableView reloadData];
        }];
}
您可以看一看。它是的Objective-C实现,还有一些特性。(我是作者)

使用RXPromise库的解决方案如下所示:

- (void) loadDataAndPerformActionsAfterwards {
    [self fetchMovie]
    .thenOn(dispatch_queue_get_main(), ^id(id fetchedMovie) {
        self.model = fetchedObjects;
        [self.tableView reloadData];
    }, nil);
}
- (void) viewWillDisappear:(BOOL)animate {
    [super viewWillDisappear:animate];

    [self.fetchObjectsPromise cancel];
    self.fetchObjectPromise = nil;
}
这假设方法
fetchMovie
返回一个承诺

如何实现这一点?您可以轻松地将任何异步方法或操作包装成一个返回承诺的方法。这适用于任何信号方法:完成块、回调函数、委托、KVO、通知等

例如,
NSURLConnection
的异步便利类方法的简化实现(实际上,您应该检查响应并更好地处理错误):


您可能希望使用使用
NSURLConnection
委托的方法,或者使用
NSOperation
子类的方法。这使您能够实现取消:

在这里,HTTPOperation对象将侦听其自己的promise以获取错误信号。如果它接收到一个错误信号,例如从另一个对象发送到promise的cancel消息,则处理程序会将
cancel
消息“转发”给操作

例如,视图控制器现在可以取消正在运行的HTTPOperation,如下所示:

- (void) loadDataAndPerformActionsAfterwards {
    [self fetchMovie]
    .thenOn(dispatch_queue_get_main(), ^id(id fetchedMovie) {
        self.model = fetchedObjects;
        [self.tableView reloadData];
    }, nil);
}
- (void) viewWillDisappear:(BOOL)animate {
    [super viewWillDisappear:animate];

    [self.fetchObjectsPromise cancel];
    self.fetchObjectPromise = nil;
}
您可以看一看。它是的Objective-C实现,还有一些特性。(我是作者)

使用RXPromise库的解决方案如下所示:

- (void) loadDataAndPerformActionsAfterwards {
    [self fetchMovie]
    .thenOn(dispatch_queue_get_main(), ^id(id fetchedMovie) {
        self.model = fetchedObjects;
        [self.tableView reloadData];
    }, nil);
}
- (void) viewWillDisappear:(BOOL)animate {
    [super viewWillDisappear:animate];

    [self.fetchObjectsPromise cancel];
    self.fetchObjectPromise = nil;
}
这假设方法
fetchMovie
返回一个承诺

如何实现这一点?您可以轻松地将任何异步方法或操作包装成一个返回承诺的方法。这适用于任何信号方法:完成块、回调函数、委托、KVO、通知等

例如,
NSURLConnection
的异步便利类方法的简化实现(实际上,您应该检查响应并更好地处理错误):


您可能希望使用使用
NSURLConnection
delega的方法