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