如何从块中取出数据?

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
    ...
}