SHXPromise 为组织异步代码提供了简单的工具。
具体来说,它是在 Objective-C 中实现的 Promises/A+ 规范的微型版本。
它适用于 iOS(5.0 及以上版本)和 OS X(10.7 及以上版本)。
即使值已经可用,它也会异步传递所有承诺,帮助您编写在底层数据提供者从同步转换为异步时不会变化的代码。
有几种不同的安装选项
无论使用哪种安装方法,您都可以通过在需要的位置简单地导入 SHXPromise 类来开始使用 SHXPromise 类。
#import "SHXPromise.h"
SHXPromise 实际上只是两个文件:**SHXPromise.h** 和 **SHXPromise.m**。您可以克隆此仓库,然后将这两个文件拖放到您的 Xcode 项目中。请确保选中“将项目进入目标组文件夹(如有必要)”复选框,并确认主项目目标被选中,并且没有名称冲突。
SHXPromise *promise = [[SHXPromise alloc] init];
[promise onFulfilled:^id(id value) {
// success
} rejected:^id(NSError *reason) {
// failure
}];
// on succeed
[promise resolve:value];
// on reject
[promise reject:reason];
一旦承诺已被解决或拒绝,则无法再次解决或拒绝。
以下是一个简单的 AFNetworking 封装示例
- (SHXPromise *)getJSON:(NSString *)urlString {
SHXPromise *promise = [[SHXPromise alloc] init];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
[promise fulfill:JSON];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
[promise reject:error];
}];
[operation start];
return promise;
}
Promises/A+ 承诺的真正厉害特性之一是它们可以链接在一起。换句话说,第一个解决处理程序的返回值将被传递到第二个解决处理程序。
如果您返回一个常规值,它将被原样传递给下一个 fulfilled
处理程序。
[[[self getJSON:@"posts.json"] onFulfilled:^id(id json) {
return [value objectForKey:@"post"];
}] onFulfilled:^id(id post) {
// proceed
}];
如果您返回一个 NSError 对象,它将被传递到下一个 rejected
处理程序
[[[self getJSON:@"posts.json"] onFulfilled:^id(id json) {
return [NSError errorWithDomain:@"SHXTest" code:1 userInfo:@{}];
}] onRejected:^id(NSError *reason) {
// handle error
}];
真正厉害的部分来自您从第一个处理程序返回一个承诺
[[[self getJSON:@"posts/1.json"] onFulfilled:^id(id post) {
return [self getJSON:[post objectForKey:@"commentURL"]];
}] onFulfilled:^id(id comments) {
// proceed with access to posts and comments
}];
这允许您简化嵌套回调,也是承诺的主要特性,可以防止在具有大量异步代码的程序中产生“内向漂移”。
错误也会传播。您可以使用此功能模拟同步代码中的 try/catch
逻辑。只需按需链式连接解决回调,并在末尾添加一个错误处理程序来捕获错误。
[[[self getJSON:@"posts/1.json"] onFulfilled:^id(id post) {
return [self getJSON:[post objectForKey:@"commentURL"]];
}] onFulfilled:^id(id comments) {
// proceed with access to posts and comments
}] onRejected:^id(NSError *reason) {
// handle errors in either of the two requests
}];
有时你可能需要同时处理多个承诺。如果你将承诺数组传递给 all:
方法,它将返回一个新的承诺,在数组中所有的承诺都得到解决时才会解决;如果数组中的任何一个承诺被拒绝,会立即拒绝。
NSArray *postURLs = @[...];
NSMutableArray *promises = [NSMutableArray array];
for (NSString *url in postURLs) {
[promises addObject:[self getJSON:url]];
}
[[SHXPromise all:promises] onFulfilled:^id(id posts) {
// posts contains an array of results for the given promises
}];
有时你可能需要同时处理多个承诺。如果你将承诺词汇传递给 dictionary:
方法,它将返回一个新的承诺,在词汇表中的所有承诺都得到解决时才会解决;如果词汇表中的任何一个承诺被拒绝,会立即拒绝。
all:
方法的不同之处在于,dictionary:
函数的解决方案值和参数都是对象字面量。这允许你直接从返回的对象引用结果,而无需记住与 all:
一样的初始顺序。
NSDictionary *promises = @{
@"posts": [self getJSON:@"posts.json"],
@"users": [self getJSON:@"users.json"],
};
[[SHXPromise dictionary:promises] onFulfilled:^id(id results) {
NSLog(@"%@", [results objectForKey:@"posts"]); // print the users.json results
NSLog(@"%@", [results objectForKey:@"users"]); // print the posts.json results
}];
Stefan Huber
SHXPromise 在 MIT 许可证下可用。更多信息请参阅 LICENSE 文件。