Ios 如何返回在块之后的延迟时间内确定的值?

Ios 如何返回在块之后的延迟时间内确定的值?,ios,objective-c,objective-c-blocks,Ios,Objective C,Objective C Blocks,对于Objective-C来说,这是一个非常新的概念,并且很难弄清楚如何完成以下任务。我来自javascript背景,因此我可能没有以正确的方式处理这个问题 在我的视图控制器中,我正在调用一个类方法getluminomity。我想从相机中收集一些浮点值,持续7秒,求平均值,然后返回平均值,但不知道如何做。这是我的getLuminosity代码: - (CGFloat) getLuminosity { ... [vidCam startCameraCapture];

对于
Objective-C
来说,这是一个非常新的概念,并且很难弄清楚如何完成以下任务。我来自javascript背景,因此我可能没有以正确的方式处理这个问题

在我的视图控制器中,我正在调用一个类方法
getluminomity
。我想从相机中收集一些
浮点值
,持续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;

}

谢谢你的帮助

dispatch\u after
与javascript中的
setTimeout
相同。您不能返回其中任何一个的内容

您有两种选择,或者将当前线程休眠7秒(处理器将使用CPU核心执行其他任务7秒,然后返回):

或提供回调块:

- (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) {
  ...
}];

基本上有两种方法。第一种方法是以块同步方式实现
getluminomity
方法,这不是一个好主意。第二种方法是使用异步模式,例如使用委托、块或(无耻的自我提升,尽管有更多的实现可用)

既然你有JS的背景,我想你对“承诺”这个词很熟悉。以下代码片段显示了如何使用Objective-C中的承诺来完成此任务:

#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;
}

您的方法
getluminomity
调用一个异步方法。这不可避免地使调用方法也变得异步

因此,工作方法的第一步是认识到您的方法
getluminomity
是异步的,并且异步方法应该提供一种方法来向调用站点发出信号,表明底层异步任务已经完成:

我们可以使用“完成处理程序”来实现这一点,但请记住,这不是实现这一点的唯一方法(请参阅@b52-answer如何通过承诺实现这一点)

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

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

typedef void (^completion_t)(NSNumber* averageLumin, NSError* error);
注意:通常情况下,完成处理程序的“类型”将由底层异步任务及其需求分别定义。不过,块的实现将由调用站点提供

然后,您的异步方法可以如下所示:

- (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];
                ...


            });
        }             
    }];

}

谢谢你的回答。这是非常有用的。一项澄清。我是否将typedef行放在视图控制器的接口部分?你评论的下一行应该放在我的Luminosity class.h文件中吗?typedef是为了方便。异步方法的原型和完成处理程序的typedef属于一起(即,当异步方法的声明位于接口部分时,如果接口也是,则将typedef放在顶部,否则将其保留在实现文件中)。注意:您也可以声明异步方法,而无需为完成处理程序使用typedef,如许多Apple API中所示。注意:通常,您在@implementation部分定义方法而无需声明它们。如果您希望在实现中声明私有方法,通常会在实现文件中使用“类扩展”接口或类别。我不建议使用
typedef
s,因为它会使代码在本地不那么明显,并阻止正确的自动完成魔法。非常感谢。我让它工作了:)
- (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];
                ...


            });
        }             
    }];

}