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

对于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; } 

谢谢你的帮助!

getLuminosity方法调用一个asynchronous方法。 这不可避免地使调用方法也是asynchronous的!

所以,工作方法的第一步是意识到你的方法getLuminosityasynchronous的 ,而一个asynchronous方法应该提供一种方法来告诉调用站点底层的asynchronous任务已经完成:

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

完成处理程序 – 一个更精确的块 – 需要由呼叫站点定义(即实现)。 当调用站点“启动”asynchronous任务(通过调用asynchronous方法)完成处理程序被传递给asynchronous任务。 任务的责任是在完成处理程序时“调用”完成处理程序。

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

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

注意:通常,完成处理程序的“types”将由底层的asynchronous任务及其需求分别定义。 该块的实现将由呼叫站点提供

你的asynchronous方法可以看起来像这样:

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

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

你有两个select,要么把当前线程hibernate7秒(处理器将使用CPU核心的东西7秒,然后回来):

 - (CGFloat) getLuminosity { ... [vidCam startCameraCapture]; [NSThread sleepForTimeInterval:7.0]; [vidCam stopCameraCapture]; NSNumber *averageLumin = [_arrayOfLumins valueForKeyPath:@"@avg.self"]; return [averageLumin floatValue]; } 

或者提供一个callback块:

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

基本上有两种方法。 第一个方法是以阻塞同步方式实现getLuminosity方法,这不是一个好主意。 第二个是使用asynchronous模式,例如使用委托,阻止或承诺 (无耻的自我推销,尽pipe有更多的实现可用)。

既然你有一个JS的背景,我假设你熟悉术语诺言 。 以下片段展示了如何使用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); }];