如何从块中取出数据?
How to get data out of a block?
我正在尝试为 objective-c 中的 ios 进行同步的 .NET recognize() 调用。我找到了识别语音的代码,但识别出的字符串只在一个块内。
我试过使块不是块(它似乎是 API 的一部分,它是块),制作 __block 变量并 returning 它们值,也是块 caller/declarer 中的参数;最后我在块中写了一个文件并在外面读取文件。它仍然没有像我想要的那样工作,因为它是异步的,尽管我至少得到了一些数据。我还尝试从块内部写入一个全局变量并在外部读取它。
我正在使用这里的代码:How to implement speech-to-text via Speech framework,这是(在我破坏它之前):
/*!
* @brief Starts listening and recognizing user input through the
* phone's microphone
*/
- (void)startListening {
// Initialize the AVAudioEngine
audioEngine = [[AVAudioEngine alloc] init];
// Make sure there's not a recognition task already running
if (recognitionTask) {
[recognitionTask cancel];
recognitionTask = nil;
}
// Starts an AVAudio Session
NSError *error;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryRecord error:&error];
[audioSession setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error];
// Starts a recognition process, in the block it logs the input or stops the audio
// process if there's an error.
recognitionRequest = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
AVAudioInputNode *inputNode = audioEngine.inputNode;
recognitionRequest.shouldReportPartialResults = YES;
recognitionTask = [speechRecognizer recognitionTaskWithRequest:recognitionRequest resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
BOOL isFinal = NO;
if (result) {
// Whatever you say in the microphone after pressing the button should be being logged
// in the console.
NSLog(@"RESULT:%@",result.bestTranscription.formattedString);
isFinal = !result.isFinal;
}
if (error) {
[audioEngine stop];
[inputNode removeTapOnBus:0];
recognitionRequest = nil;
recognitionTask = nil;
}
}];
// Sets the recording format
AVAudioFormat *recordingFormat = [inputNode outputFormatForBus:0];
[inputNode installTapOnBus:0 bufferSize:1024 format:recordingFormat block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
[recognitionRequest appendAudioPCMBuffer:buffer];
}];
// Starts the audio engine, i.e. it starts listening.
[audioEngine prepare];
[audioEngine startAndReturnError:&error];
NSLog(@"Say Something, I'm listening");
}
我想调用 Listen()(如上面的 startListening()),让它在完成之前阻止执行,并让它 return 说出的字符串。但实际上,我很高兴能以某种方式将 result.bestTranscription.formattedString 发送给 startListening() 的调用者。
我建议您采用另一种方法。在 Objective-C 中,具有长时间阻塞的函数是一种反模式。
这种语言没有 async/await,也没有协作式多任务处理,因此长时间阻塞可能会导致资源泄漏和死锁。此外,如果在主线程(应用程序 UI 运行的地方)完成,应用程序可能会因无响应而被系统强制终止。
您应该使用一些异步模式,例如委托或回调。
您也可以尝试使用一些 promises 库来稍微线性化您的代码,并使其看起来 "sequential"。
最简单的回调方法是将完成块传递给您的 "recognize" 函数,并在完成时使用结果字符串调用它:
- (void)recognizeWithCompletion:(void (^)(NSString *resultString, NSError *error))completion {
...
recognitionTask = [speechRecognizer recognitionTaskWithRequest:recognitionRequest
resultHandler:^(SFSpeechRecognitionResult *result, NSError *error)
{
...
dispatch_async(dispatch_get_main_queue(), ^{
completion(result.bestTranscription.formattedString, error);
});
...
}];
...
}
请注意,第二个参数 (NSError) - 是一个错误,以防调用者也想对此做出反应。
来电方:
// client side - add this to your UI code somewhere
__weak typeof(self) weakSelf = self;
[self recognizeWithCompletion:^(NSString *resultString, NSError *error) {
if (!error) {
[weakSelf processCommand:resultString];
}
}];
// separate method
- (void)processCommand:(NSString *command) {
// can do your processing here based on the text
...
}
我正在尝试为 objective-c 中的 ios 进行同步的 .NET recognize() 调用。我找到了识别语音的代码,但识别出的字符串只在一个块内。
我试过使块不是块(它似乎是 API 的一部分,它是块),制作 __block 变量并 returning 它们值,也是块 caller/declarer 中的参数;最后我在块中写了一个文件并在外面读取文件。它仍然没有像我想要的那样工作,因为它是异步的,尽管我至少得到了一些数据。我还尝试从块内部写入一个全局变量并在外部读取它。
我正在使用这里的代码:How to implement speech-to-text via Speech framework,这是(在我破坏它之前):
/*!
* @brief Starts listening and recognizing user input through the
* phone's microphone
*/
- (void)startListening {
// Initialize the AVAudioEngine
audioEngine = [[AVAudioEngine alloc] init];
// Make sure there's not a recognition task already running
if (recognitionTask) {
[recognitionTask cancel];
recognitionTask = nil;
}
// Starts an AVAudio Session
NSError *error;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryRecord error:&error];
[audioSession setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error];
// Starts a recognition process, in the block it logs the input or stops the audio
// process if there's an error.
recognitionRequest = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
AVAudioInputNode *inputNode = audioEngine.inputNode;
recognitionRequest.shouldReportPartialResults = YES;
recognitionTask = [speechRecognizer recognitionTaskWithRequest:recognitionRequest resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
BOOL isFinal = NO;
if (result) {
// Whatever you say in the microphone after pressing the button should be being logged
// in the console.
NSLog(@"RESULT:%@",result.bestTranscription.formattedString);
isFinal = !result.isFinal;
}
if (error) {
[audioEngine stop];
[inputNode removeTapOnBus:0];
recognitionRequest = nil;
recognitionTask = nil;
}
}];
// Sets the recording format
AVAudioFormat *recordingFormat = [inputNode outputFormatForBus:0];
[inputNode installTapOnBus:0 bufferSize:1024 format:recordingFormat block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
[recognitionRequest appendAudioPCMBuffer:buffer];
}];
// Starts the audio engine, i.e. it starts listening.
[audioEngine prepare];
[audioEngine startAndReturnError:&error];
NSLog(@"Say Something, I'm listening");
}
我想调用 Listen()(如上面的 startListening()),让它在完成之前阻止执行,并让它 return 说出的字符串。但实际上,我很高兴能以某种方式将 result.bestTranscription.formattedString 发送给 startListening() 的调用者。
我建议您采用另一种方法。在 Objective-C 中,具有长时间阻塞的函数是一种反模式。
这种语言没有 async/await,也没有协作式多任务处理,因此长时间阻塞可能会导致资源泄漏和死锁。此外,如果在主线程(应用程序 UI 运行的地方)完成,应用程序可能会因无响应而被系统强制终止。
您应该使用一些异步模式,例如委托或回调。
您也可以尝试使用一些 promises 库来稍微线性化您的代码,并使其看起来 "sequential"。
最简单的回调方法是将完成块传递给您的 "recognize" 函数,并在完成时使用结果字符串调用它:
- (void)recognizeWithCompletion:(void (^)(NSString *resultString, NSError *error))completion {
...
recognitionTask = [speechRecognizer recognitionTaskWithRequest:recognitionRequest
resultHandler:^(SFSpeechRecognitionResult *result, NSError *error)
{
...
dispatch_async(dispatch_get_main_queue(), ^{
completion(result.bestTranscription.formattedString, error);
});
...
}];
...
}
请注意,第二个参数 (NSError) - 是一个错误,以防调用者也想对此做出反应。
来电方:
// client side - add this to your UI code somewhere
__weak typeof(self) weakSelf = self;
[self recognizeWithCompletion:^(NSString *resultString, NSError *error) {
if (!error) {
[weakSelf processCommand:resultString];
}
}];
// separate method
- (void)processCommand:(NSString *command) {
// can do your processing here based on the text
...
}