Cocoa touch 如何使用ReactiveCocoa实现承诺模式?
我是刚接触iOS开发的,来自于EmberJS的JS背景。我想将我的EmberJS应用程序移植到iOS应用程序。因此,我想在我的iOS应用程序中使用类似的结构。当EmberJS大量使用promises时,我在iOS上搜索了类似的东西,偶然发现了ReactiveCocoa在ReactiveCocoa的介绍中说,这个框架可以用来实现承诺。我尝试过,但它不能正常工作。我想从一个非常简单的例子开始:Cocoa touch 如何使用ReactiveCocoa实现承诺模式?,cocoa-touch,reactive-cocoa,Cocoa Touch,Reactive Cocoa,我是刚接触iOS开发的,来自于EmberJS的JS背景。我想将我的EmberJS应用程序移植到iOS应用程序。因此,我想在我的iOS应用程序中使用类似的结构。当EmberJS大量使用promises时,我在iOS上搜索了类似的东西,偶然发现了ReactiveCocoa在ReactiveCocoa的介绍中说,这个框架可以用来实现承诺。我尝试过,但它不能正常工作。我想从一个非常简单的例子开始: 发出异步网络请求(以填充UITableViewController)。从该方法返回承诺 订阅此承诺,并在
- 发出异步网络请求(以填充UITableViewController)。从该方法返回承诺
- 订阅此承诺,并在完成后重新加载TableView
- 我的TableView不会在请求完成后立即重新加载。
- 请求完成后,我立即在订阅中看到日志语句已完成。但是TableView保持空白
- TableView在等待几秒钟后加载数据
- 如果在看到日志输出后开始滚动TableView,TableView会突然被加载
subscribebcompleted
)的解决也可能发生在后台线程中,Cocoa Touch可能不喜欢这样。我说得对吗?但如果是这样,我该如何履行承诺
我希望你能帮助我开始使用ReactiveCocoa。Thx!:-)
更新:
我设法通过将toreloadData
包装在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的方法