在我的代码中,我正在运行本地服务器(CocoaHTTPServer)。当服务器收到请求时,它会创建一个线程并将控制传递给某个方法( - (NSObject<HTTPResponse> *)httpResponseForMethod:(NSString *)method URI:(NSString *)path
,这里可能不相关)。
我需要阅读本地资产列表并返回结果。 API调用([assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) ...
)是异步的。
由于HTTPResponse需要等到API调用完成,我创建了一个名为_isProcessing
的标志,我在进行API调用之前设置了该标志。调用完成后,我取消设置标志并返回HTTP请求。等待的代码如下:
// the API call is non-blocking. hence, wait in a loop until the command has finished
samCommand->isProcessing = YES;
while (samCommand->isProcessing) {
usleep(100*1000);
}
API调用在完成任务后调用委托方法,如下所示:
// to be called at the end of an asynch operation (eg: reading local asset list)
- (void) commandDidFinish {
// flag to open the lock
isProcessing = NO;
}
这可行,但可能需要性能增强。我如何在这里使用任何东西(运行循环等)来改善性能。
按照weichsel的解决方案,我创建了一个信号量。我的代码序列是:
因此我在适当的位置嵌入了信号量。但是,信号量的等待循环有时并没有结束。正常输出应为:
2014-02-07 11:27:23:214 MM2Beta[7306:1103] HTTPServer: Started HTTP server on port 1978
2014-02-07 11:27:23:887 MM2Beta[7306:6303] created semaphore 0x1f890670->0x1f8950a0
2014-02-07 11:27:23:887 MM2Beta[7306:6303] calling execute with 0x1f890670
2014-02-07 11:27:23:887 MM2Beta[7306:6303] starting wait loop 0x1f890670->0x1f8950a0
2014-02-07 11:27:23:887 MM2Beta[7306:907] calling getAssetsList with delegate 0x1f890670
2014-02-07 11:27:24:108 MM2Beta[7306:907] calling delegate [0x1f890670 commandDidFinish]
2014-02-07 11:27:24:108 MM2Beta[7306:907] releasing semaphore 0x1f890670->0x1f8950a0
2014-02-07 11:27:24:109 MM2Beta[7306:6303] ending wait loop 0x1f890670->0x0
在每次运行中,最后一步(ending wait loop 0x1f890670->0x0
都没有发生)。因此,等待循环永远不会结束。有时代码崩溃,恰好在同一点。任何线索在这里有什么不妥。
我的代码如下:
@implementation SAMCommand {
NSData* resultData;
dispatch_semaphore_t semaphore; // a lock to establish whether the command has been processed
}
// construct the object, ensuring that the "command" field is present in the jsonString
+(NSData*) createAndExecuteCommandWithJSONParamsAs:(NSString *)jsonString {
SAMCommand* samCommand = [[SAMCommand alloc] init];
samCommand.commandParams = [jsonString dictionaryFromJSON];
if(COMPONENT==nil || COMMAND==nil){
DDLogError(@"command not found in %@",jsonString);
return nil;
}
samCommand->semaphore = dispatch_semaphore_create(0);
DDLogInfo(@"created semaphore %p->%p",samCommand,samCommand->semaphore);
// to execute a command contained in the jsonString, we use reflection.
DDLogInfo(@"calling execute with %p",samCommand);
[NSClassFromString(COMPONENT) performSelectorOnMainThread:NSSelectorFromString([NSString stringWithFormat:@"%@_%@_%@:",COMMAND,MEDIA_SOURCE,MEDIA_TYPE]) withObject:samCommand waitUntilDone:NO];
// the above calls are non-blocking. hence, wait in a loop until the command has finished
DDLogInfo(@"starting wait loop %p->%p",samCommand,samCommand->semaphore);
dispatch_semaphore_wait(samCommand->semaphore, DISPATCH_TIME_FOREVER);
DDLogInfo(@"ending wait loop %p->%p",samCommand,samCommand->semaphore);
DDLogInfo(@"");
// return the data
return samCommand->resultData;
}
// to be called at the end of an asynch operation (eg: reading local asset list)
- (void) commandDidFinish {
// flag to release the lock
DDLogInfo(@"releasing semaphore %p->%p",self,semaphore);
dispatch_semaphore_signal(semaphore);
semaphore = nil;
}
@end
我得到了它的工作:)
最后,似乎运行稳定的是创建信号量,并将其传递给ALAsset异步API调用,并在调用结束时释放它。之前,我正在调用我创建信号量的类的委托方法,并且信号量对象以某种方式获得释放。不确定那里发生了什么。
答案 0 :(得分:0)
NSRunLoop有一个名为runUntilDate的方法:它应该适用于你在不久的将来提前1个左右的日期。这样你就可以在while循环中替换你的sleep调用,例如:
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeintervalSinveNow:1]
答案 1 :(得分:0)
您可以使用信号量阻止当前队列的执行,直到另一个队列返回 基本模式是:
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[assetsLibrary enumerateAssetsUsingBlock^(ALAsset *result, NSUInteger index, BOOL *stop):^{
...
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_release(semaphore);
您可以在Apple的MTAudioProcessingTap Xcode项目中找到此方法的完整示例:
https://developer.apple.com/library/ios/samplecode/AudioTapProcessor
相关的行从MYViewController.m开始:86