OMPromises 0.8.1

OMPromises 0.8.1

测试已测试
Lang语言 Obj-CObjective C
许可证 MIT
发布最新发布2016年2月

Oliver Mader维护。



  • Oliver Mader

Promises/A启发,经过一定修改和添加,以更好地适应常见的Objective-C模式的一个经过测试和完全文档化的promises库。

如果您对promises一无所知,我建议您阅读一些文章和教程,例如1234。一些方法名称可能不同,但基本的思路大致相同。

特性

以下是OMPromises的主要特性。

  • 完全测试和文档化
  • 清新的接口和问题分解
  • 支持链式和回调,使用then:rescue:fulfilled:failed:progressed:,类似于大多数其他库
  • 链式块被异常保护
  • 支持进度通知,这与其他库不同
  • 可选支持取消
  • 如果需要,根据队列执行块
  • 各种组合器

安装

安装OMPromises的推荐方法是使用CocoaPods包管理器。

pod 'OMPromises', '~> 0.8.1'

文档

所有公共类、方法和属性都进行了文档化,因此OMPromises的每个副本都包含相应的头文件中的完整文档。

使用appledoc渲染的在线版本,阅读起来更方便,可以在这里找到。

概览

创建 - 创建promises

Promises由类型为OMPromise的对象表示。创建已经实现、失败或延迟的promises,可以使用以下静态方法之一。

OMPromise *promise = [OMPromise promiseWithResult:@1337];
// promise.state == OMPromiseStateFulfilled
// promise.result == @1337

OMPromise *promise1SecLate = [OMPromise promiseWithResult:@1338 after:1.f];
// promise1SecLate.state == OMPromiseStateUnfulfilled
// promise1SecLate.result == nil
// ... after 1 second ..
// promise1SecLate.state == OMPromiseStateFulfilled
// promise1SecLate.result == @1338

OMPromise *failed = [OMPromise promiseWithError:[NSError ...]];
// failed.state == OMPromiseStateFailed
// failed.error == [NSError ...]

// To delay the fail use promiseWithError:after: similar to promiseWithResult:after:

Promises的一个特殊属性是,它们只能从未实现状态到失败实现状态进行一次状态转换。承诺本身不提供进行此类转换的接口。这就是为什么存在一个称为OMDeferred的父类的原因,它产生一个承诺,是唯一可以改变相应承诺状态的权利机构。

因此,在上面的示例中使用的承诺是只读的。要创建承诺,你可能实际上需要创建一个异步任务,你应该为自己保留它,并返回一个与新创建的异步任务对应的承诺。为了保持对承诺的了解,你可能可以使用progress:多次,然后最多使用一次在异步任务上的fulfil:fail:

- (OMPromise *)workIntensiveButSynchronousMethod {
    OMDeferred *deferred = [OMDeferred new];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // do your long-running task, eventually provide information about the progress..
        while (running)
            [deferred progress:progress];

        if (failed) {
            [deferred fail:error];
        } else {
            [deferred fulfil:result];
        }
    });

    return deferred.promise;
}

如果你不需要进度,你也可以简化上面的代码片段,如下所示

- (OMPromise *)workIntensiveButSynchronousMethod {
    return [OMPromise promiseWithTask:^{
        // do the long running task
        // ...

        // once we are done, we return the result, an NSError is automatically
        // treated as failure
        return (failed) ? error : result;
    } on:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
}

回调 - 对状态变化的响应

一旦你获得了OMPromise的实例,你可能想对状态变化做出反应。这是通过注册来完成的,使用的方法是fulfilled:failed:和/或progressed:,如果发生了相应的事件,这些方法会被调用。这些方法返回self以简单地链接多个调用,并允许注册对同一事件的多个回调。

[[OMPromise promiseWithResult:@1337 after:1.f]
    fulfilled:^(id result) {
        // called after 1 second, result == @1337
    }];

OMPromise *networkRequest = [OMHTTPRequest get:@"http://google.com"
                                    parameters:nil
                                       options:nil];
[[[networkRequest
    fulfilled:^(OMHTTPResponse *response) {
        // called if the network request succeeded
    }]
    failed:^(NSError *error) {
        // otherwise ...
    }]
    progressed:^(float progress) {
        // describes the progress as a value between 0.f and 1.f
    }];

链式调用 - 依赖于其他承诺创建承诺

有时可能需要链式调用承诺,并通过一个承诺本身来表示链。例如,创建由承诺描述的小部分,并使用某些方法将这些小部分组合成更大的整体。

通过使用名为then:的方法实现所描述的行为。类似于fulfil:,它会执行一个在承诺得到解决后被执行的块,但该块必须返回一个值。这个值可能是一个新的承诺或任何其他对象,然后它被绑定到由then:返回的新创建的承诺。如果链中的任何承诺失败,则整个链都会失败,并且会跳过所有连续的then块。

// get User by its email
- (OMPromise *)getUserByEmail:(NSString *email);

// get all Comments created by a User
- (OMPromise *)getCommentsOfUser:(User *)user;

// get all Comment messages by a User having a certain email address
- (OMPromise *)getCommentsByUsersEmail:(NSString *)email {
    OMPromise *chain = [[[self getUserByEmail:email]
        then:^id(User *user) {
            // we can chain by returning other promises
            return [self getCommentsOfUser:user];
        }]
        then:^id(NSArray *comments) {
            // but also any other object to perform e.g. value transformations
            NSMutableArray *commentMessages = [NSMutableArray array];
            for (Comment *comment in comments) {
                [commentMessages addObject:comment.message];
            }
            return commentMessages;
        }];

    // chain fails if either the first promise, returned by getUserByEmail:,
    // or the second once, returned by getCommentsOfUser:, fails;
    // otherwise the results are propagated from promise to promise until the
    // last promise, representing the chain, is fulfilled
    return chain;
}

在某些情况下,可能需要从失败中恢复并让链继续,就好像一切都没有发生错误一样。这就是rescue:发挥作用的时候。它返回一个新创建的承诺,但是提供给它的块如果在承诺失败时会调用。

// yields an UIImage if the user supplied an avatar
- (OMPromise *)getAvatarForUser:(User *)user;

// always returns an UIImage being either the User's supplied one or a dummy image
- (OMPromise *)getAvatarOrDummyForUser:(User *)user {
    OMPromise *chain = [[self getAvatarForUser:user]
        rescue:^id(NSError *error) {
            return [UIImage imageNamed:@"dummy_image.png"];
        }];

    // chain gets fulfilled always, due to rescue:
    return chain;
}

此时,有些人可能会认识到这与范畴论中单子的相似之处。如果不熟悉,你可以查阅Haskell及其概念。

取消 - 终止正在进行的操作

如果你抽象的操作很重且运行时间很长,你可能需要支持取消。它允许承诺的所有者取消承诺,从而取消长时间运行的操作(如果可能的话)。一旦取消承诺,它就会进入失败状态,并带有特定的错误代码。

默认情况下,承诺不可撤销,但异步任务的所有者可以通过使用cancelled:注册至少一个取消处理器来使其可行。根据任务和用例是否需要实现取消处理器,这是有意义的。

- (OMPromise *)get100GofData {
    OMDeferred *deferred = [OMDeferred new];
    [deferred cancelled:^(OMDeferred *this) {
        // cancel the download..
    }];
    return deferred.promise;
}

- (void)startDownloadAndAbort {
    OMPromise *dl = [self get100GofData];
    // dl.cancellable == YES

    // ...
    // for an unknown reason we dont need it anymore
    [dl cancel];

    // if cancelled, it switches into the failed state
    [dl failed:^(NSError *error) {
        // error.domain == OMPromisesErrorDomain
        // error.code == OMPromisesCancelledError
    }];
}

组合器 & 转换器 - 在链之外形成承诺的组合

目前仅提供以下组合器,请查阅文档获取更详细的信息。每个组合器都假设提供给所有承诺的工作负载均匀分配,从而创建合理的进度组合。

  • join - 移除一层承诺封装
  • chain:initial: - 等同于应用多个链式/回调调用
  • all: - 等待所有承诺得到解决,如果有任何承诺失败,则失败。
  • any: - 如果提供的任何一个promise被满足,则返回满足的结果,否则失败。
  • collect: - 收集所需承诺的全部结果,因此它永远不会失败。
  • relay: - 将所有承诺事件转发到另一个延迟承诺。

许可

OMPromises遵循MIT许可证条款。请查阅LICENSE文件以获取详细信息。