CKPromise 1.5.1

CKPromise 1.5.1

测试已测试
Lang语言 Objective C++Objective C++
许可证 MIT
发布上次发布2015年11月

Cristian Kocza维护。



CKPromise 1.5.1

  • 作者:
  • Cristian Kocza

这是符合 Promises/A+ 规范的 Objective-C 实现。完整规范可以在 http://promisesaplus.com/ 找到。

这个实现遵循所有 Promise/A+ 规范,除了不适用于 ObjectiveC 的那些(特别是第 2.3.3 节)。

当前的实现还没有实现循环 promise 链检测,这个功能将在以后添加。

新特性

添加了对 Swift 的支持,请检查 CKSwiftPromise 框架(如果您使用 Cocoapods,则请检查 CKSwiftPromise spec)。

安装

通过 GitHub

  1. git clone https://github.com/cristik/CKPromise.git
  2. CKPromise.xcproject 添加到您的项目/工作区
  3. 链接到 CKPromise 或/和 CKSwiftPromise 目标

描述

promises 的主要优势之一是它们可以帮助避免回调地狱。例如,考虑一个添加书籍的序列,但在添加它之前,需要与服务器验证书籍详情,添加后需要获取全部细节。

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *bookData = @{@"name": @"Harry Potter"};
void (^failureBlock)(NSError *error) = ^(NSError *error) {
if([error.domain isEqual:NSURLErrorDomain]) {
// inform the user that there was a server communication problem
} else {
// inform the user that the book could not be added (e.g. it was already added by someone else)
}
};
[manager POST:@"http://myserver.com/validator/book" 
parameters:bookData
success:^(AFHTTPRequestOperation *operation, id responseObject) {
[manager POST:@"http://myserver.com/book"
parameters:bookData
success:^(AFHTTPRequestOperation *operation, id responseObject) {
[manager GET:[@"http://myserver.com/book/" stringByAppendingString:responseObject]
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
// inform the user that the book was added, move to the appropriate screen
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
failureBlock(operation, error);
}];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
failureBlock(operation, error);
}];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
failureBlock(operation, error);
}];

这会导致 3 个 HTTP 请求调用,每个调用有 3 个成功+失败处理程序,以及大量的缩进代码。Promises 通过允许创建链来解决这个问题,每个处理器都在前一个完成后被调用。

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *bookData = @{@"name": @"Harry Potter"};
return [manager POST:@"http://myserver.com/validator/book" parameters:bookData].promise.done(^{
return [manager POST:@"http://myserver.com/book" parameters:bookData].promise;
}).success(^(NSString *bookId){
NSString *url = [@"http://myserver.com/book/" stringByAppendingString:bookId];
return [manager GET:url parameters:nil].promise;
}).success(^(NSDictionary *bookDetails){
// inform the user that the book was added, move to the appropriate screen
}).failure(^(NSError *error) {
if([error.domain isEqual:NSURLErrorDomain]) {
// inform the user that there was a server communication problem
} else {
// inform the user that the book could not be added (e.g. it was already added by someone else)
}
});

此外,只有一个失败回调是必需的,因为如果链中的任何 promise 失败,则链将自动前进到失败处理器,而不会执行其他处理器。

使用 promises 还有其他许多好处,您可以在我的关于 promises 的文章系列中了解更多信息:http://blog.cristik.com/2015/03/promises-and-objectivec-no-more-callback-hell/

用法

您可以使用 [[CKPromise alloc] init] 或使用便利初始化器 [CKPromise promise] 来创建一个 promise。

拥有一旦 promise,您可以调用适当的方来解决或拒绝它: resolve:,或 reject:

如果您想添加回调来跟踪 promise 的解决,可以使用以下

  • then: 方法,允许传递两个回调,一个用于成功,一个用于失败。示例
[promise then: ^{
NSLog(@"Succeeded");
} :^(NSError* err){
NSLog(@"Failed: %@", err);
}];
  • then 属性,它返回一个接受两个参数的块,这些参数为成功/失败回调示例
promise.then(^(NSNumber *count){
NSLog(@"Number of records: %@", count);
}, ^{
NSLog(@"Failed");
});
  • 提供了 then::then 的调度队列变体,允许指定回调应该执行的调度队列。默认情况下,回调将在主线程上调度,如果需要的话请使用这些方法。
  • 其他便捷方法和属性:then:success:successfailure:failurealways:always

回调参数非常灵活,允许回调返回一个id,或者不返回任何内容(void),并接收一个参数或没有参数(取决于你是否有兴趣知道promise的结果或失败原因)。因此,所有以下回调都是合法的

void^(){}
void^(id value){}
void^(NSNumber *result){}
id^(){return @15;}
id^(NSError *err){NSLog(@"Failed with error: %@", error); return [CKPromise rejected:err];}

这允许非常定制的promise链,例如

[backgroundManagedObjectContext insertNewObject:@"User"].success(CKPromise* ^(NSString *uuid){
return [mainObjectConext fetchObjectOfType:@"User" withId:uuid];
}).success(void ^(NSManagedObjectContext *user){
//send the user to UI
}).failure(void ^(NSError* err){
NSLog(@"Encountered an error: %@", err);
})