如何返回delay_after块中确定的值?

时间:2014-04-05 07:25:57

标签: ios objective-c objective-c-blocks

对于Objective-C来说非常新,并且很难搞清楚如何完成以下操作。我来自javascript背景,所以我可能不会以正确的方式接近它。

在我的视图控制器中,我正在调用类方法getLuminosity。我想从相机中收集一些float,持续7秒,取平均值,然后返回平均值,但不知道怎么做。这是我的getLuminosity代码:

- (CGFloat) getLuminosity {

    ...

    [vidCam startCameraCapture];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [vidCam stopCameraCapture];
        NSNumber *averageLumin = [_arrayOfLumins valueForKeyPath:@"@avg.self"];
        return [averageLumin floatValue];
    });

    return floatFromDispatchBlock;

}

感谢您的帮助!

3 个答案:

答案 0 :(得分:0)

dispatch_after与javascript中的setTimeout相同。你不能返回任何一个的内容。

您有两个选项,要么让当前线程休眠7秒钟(处理器将使用CPU内核进行其他操作7秒,然后再回到它):

- (CGFloat) getLuminosity {

    ...

    [vidCam startCameraCapture];

    [NSThread sleepForTimeInterval:7.0];

    [vidCam stopCameraCapture];
    NSNumber *averageLumin = [_arrayOfLumins valueForKeyPath:@"@avg.self"];
    return [averageLumin floatValue];

}

或者提供一个回调块:

- (void) getLuminosityWithCallback:(void (^)(CGFloat averageLumin))callback; {

    ...

    [vidCam startCameraCapture];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [vidCam stopCameraCapture];
        NSNumber *averageLumin = [_arrayOfLumins valueForKeyPath:@"@avg.self"];

        callback(averageLumin.floatValue);
    });

}

[obj getLuminosityWithCallback:^(CGFloat averageLumin) {
  ...
}];

答案 1 :(得分:0)

基本上有两种方式。第一个是以阻塞同步方式实现getLuminosity方法,这不是一个好主意。第二种是使用异步模式,例如使用代表,块或promises(无耻的自我推销,尽管有更多的实现可用)。

由于你有JS背景,我认为你熟悉术语 promise 。以下代码段显示了如何使用Objective-C中的promise实现此类任务:

#import <OMPromises/OMPromises.h>

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

    [vidCam startCameraCapture];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [vidCam stopCameraCapture];
        NSNumber *averageLumin = [_arrayOfLumins valueForKeyPath:@"@avg.self"];
        [deferred fulfil:averageLumin];
    });

    return deferred.promise;
}

你用这种方式:

[[self getLuminosity] fulfilled:^(NSNumber *lumin) {
    NSLog(@"%@", lumin);
}];

答案 2 :(得分:0)

您的方法getLuminosity调用异步方法。这个不可避免的也使调用方法异步!

因此,工作方法的第一步是认识到您的方法getLuminosity异步,并且异步方法应该提供一种方法来向呼叫站点发信号通知底层异步任务完成:

我们可能会使用“完成处理程序”来完成此任务,但请记住,这不是实现此目的的唯一方法(请参阅@ b52回答如何使用promises实现此目的)。

完成处理程序 - 更精确的块 - 需要由调用站点定义(即实现)。当调用站点“启动”异步任务(通过调用异步方法)时,完成处理程序将传递给异步任务。任务的职责是在完成时“调用”完成处理程序。

通常,完成处理程序具有将用于传输异步任务结果的参数。例如,我们可以按如下方式定义完成块:

typedef void (^completion_t)(NSNumber* averageLumin, NSError* error);

注意:通常,完成处理程序的“类型”将由底层异步任务分别定义其要求。但是,块的实现将由 call-site 提供。

您的异步方法可能如下所示:

- (void) luminosityWithCompletion:(completion_t)completion;

可以实施:

- (void) luminosityWithCompletion:(completion_t)completion 
{
    ...

    [vidCam startCameraCapture];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [vidCam stopCameraCapture];
    NSNumber *averageLumin = [_arrayOfLumins valueForKeyPath:@"@avg.self"];

    if (completion) {
        completion(averageLumin, nil)
    }
});

在调用网站上,您可以使用“延续”来完成最终结果所需的任何操作:

- (void) foo
{        
    ...
    // Define the "continuation" with providing the completion block:
    // Put *everything* that shall be executed *after* the  result is
    // available into the completion handler:
    [self luminosityWithCompletion:^(NSNumber* result, NSError*error) {
        if (error) {
            // handle error
        }
        else {
            // continue on the main thread:
            dispatch_async(dispatch_get_main_queue(), ^{
                // using "result" on the main thread
                float lum = [result floatValue];
                ...


            });
        }             
    }];

}