Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c Obj-C从委托方法返回到块?_Objective C - Fatal编程技术网

Objective c Obj-C从委托方法返回到块?

Objective c Obj-C从委托方法返回到块?,objective-c,Objective C,我正在编写一个mac应用程序,它使用GCDWebServer库运行自己的web服务器。My app delegate处理GET请求的方式如下: __weak typeof(self) weakSelf = self; [webServer addDefaultHandlerForMethod:@"GET" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerRespons

我正在编写一个mac应用程序,它使用GCDWebServer库运行自己的web服务器。My app delegate处理GET请求的方式如下:

 __weak typeof(self) weakSelf = self;
 [webServer addDefaultHandlerForMethod:@"GET"
          requestClass:[GCDWebServerRequest class]
          processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {

              return [weakSelf handleRequest:request];

          }];
然后HandlerRequest方法返回响应数据,类似于:

return [GCDWebServerDataResponse responseWithHTML:@"<html><body><p>Hello World!</p></body></html>"];

问题是,我不知道怎么做。有没有办法从SpeechSynthesis:didFinishSpeaking方法返回到上面定义的processBlock中?

您需要在一个单独的线程上运行语音合成器,该线程有自己的运行循环,并使用锁允许请求线程等待操作在语音线程上完成

假设web服务器维护自己的线程和runloop,您可以使用应用程序的主线程运行语音合成器,并且可以使用NSCondition向web响应线程发出完成信号

没有错误处理的基本未测试示例:

@interface SynchroSpeaker : NSObject<NSSpeechSynthesizerDelegate>
- (id)initWithText:(NSString*)text outputUrl:(NSURL*)url;
- (void)run;
@end

@implementation SynchroSpeaker
{
    NSCondition* _lock;
    NSString* _text;
    NSURL* _url;
    NSSpeechSynthesizer* _synth;
}

- (id)initWithText:(NSString*)text outputUrl:(NSURL*)url
{
    if (self = [super init])
    {
        _text = text;
        _url = url;
        _lock = [NSCondition new];
    }
    return self;
}

- (void)run
{
    NSAssert(![NSThread isMainThread], @"This method cannot execute on the main thread.");
    [_lock lock];
    [self performSelectorOnMainThread:@selector(startOnMainThread) withObject:nil waitUntilDone:NO];
    [_lock wait];
    [_lock unlock];
}

- (void)startOnMainThread
{
    NSAssert([NSThread isMainThread], @"This method must execute on the main thread.");
    [_lock lock];

    //
    // Set up your speech synethsizer and start speaking
    //
}

- (void)speechSynthesizer:(NSSpeechSynthesizer *)sender didFinishSpeaking:(BOOL)success

{
    //
    // Signal waiting thread that speaking has completed
    //
    [_lock signal];
    [_lock unlock];
}

@end

GCDWebServer确实会运行到它自己的线程中,我想其中有两个线程——而不是主线程。我的解决方案需要在调用ProcessBlock时在主线程中运行代码

// NSSpeechSynthesizerDelegate method:
- (void)speechSynthesizer:(NSSpeechSynthesizer *)sender didFinishSpeaking:(BOOL)success
{
    NSLog(@"did finish speaking, success: %d", success);
    // return to processBlock...
}
我发现这种方式适合我的需要:

首先为我的AppDelegate声明弱存储:\uu弱AppDelegate*weakSelf=self;。这样我就可以访问块中的所有属性。 在块内声明对AppDelegate的强引用,如下所示:\u strong AppDelegate*strongSelf=weakSelf; 使用NSOperationQueue对齐主线程上的操作:

[[NSOperationQueue mainQueue] addOperationWithBlock:^ {

                                //Your code goes in here
                                NSLog(@"Main Thread Code");
                                [strongSelf myMethodOnMainThread];

                            }];
这样,myMethodOnMainThread肯定会在它应该运行的地方运行

为了清楚起见,我引用了我的相关代码部分:

webServer = [[GCDWebServer alloc] init];
webServer.delegate = self;

__weak AppDelegate *weakSelf = self;

// Add a handler to respond to GET requests
[webServer addDefaultHandlerForMethod:@"GET"
                         requestClass:[GCDWebServerRequest class]
                    asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) {

    __strong AppDelegate* strongSelf = weakSelf;
    [[NSOperationQueue mainQueue] addOperationWithBlock:^ {

                                    //Your code goes in here
                                    NSLog(@"Main Thread Code");
                                    [strongSelf myMethodOnMainThread];

                                }];

    GCDWebServerDataResponse* response = [GCDWebServerDataResponse responseWithJSONObject:packet];
                                completionBlock(response);


}];

从3.0版和更高版本开始,GCWebServer支持完全异步响应[1]

[webServer addDefaultHandlerForMethod:@"GET"
                         requestClass:[GCDWebServerRequest class]
                    asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) {

  // 1. Trigger speech synthesizer on main thread (or whatever thread it has to run on) and save "completionBlock"
  // 2. Have the delegate from the speech synthesizer call "completionBlock" when done passing an appropriate response

}];

[1]

谢谢您的帮助-看起来很有希望,尽管看起来我的web服务器也在主线程上运行,所以它在第一次NSAssert时崩溃了:@真糟糕。然后,您需要为语音合成器创建自己的NSThread。此线程将运行自己的nsrunlop,而不是使用-performSelectorOnMainThread:使用并传入线程。
[webServer addDefaultHandlerForMethod:@"GET"
                         requestClass:[GCDWebServerRequest class]
                    asyncProcessBlock:^(GCDWebServerRequest* request, GCDWebServerCompletionBlock completionBlock) {

  // 1. Trigger speech synthesizer on main thread (or whatever thread it has to run on) and save "completionBlock"
  // 2. Have the delegate from the speech synthesizer call "completionBlock" when done passing an appropriate response

}];