Block不会对外部财产变化做出反应

时间:2012-11-15 18:21:30

标签: objective-c ios xcode

在这里提出一些问题后,我决定运行这样的服务器:

@implementation Server
-(id)init
{
if (self = [super init])
{   
    shouldRun = true;
    __block Server* blocksafeSelf = self; // should prevent retain cycle

    myServer = ^() {
                    dispatch_async(dispatch_get_main_queue(), ^{
            NSString* currentText = controller.output.text;
            controller.outputTextField.text = [currentText stringByAppendingString:@"Server ready. \n"];
        });

        while (blocksafeSelf.shouldRun) {
           int bytes_received = recvfrom(...);
            if (bytes_received > 0) {
                switch (TYPE OF RECEIVED PACKET) {
                    case 1: {
                        dispatch_async(dispatch_get_main_queue(), ^{
                            NSString* currentText = controller.outputTextField.text;
                            controller.outputTextField.text = [currentText stringByAppendingString:@"S: Received Typ 1 "];
                        });
                        [blocksafeSelf methodToDealWithPacket:(PACKETTYPE*) buffer];
                        break;
                    }
                    ...
                    default: {
                       ...
                    }
                }

            }
        }

return self;
}
@synthesize shouldRun;

相应的.h文件:

@interface Server : NSObject {
    ServerBlock myServer;
    ....
}
@property BOOL shouldRun;
....
@end

现在我有一个ViewController,它将Server作为属性,并在其实现中使用以下方法:

// called when the user clicks the stop button
- (IBAction) clickedStop
{
    if(theServer != nil) {
        theServer.shouldRun = false;
    }
}

但是,当我单击停止按钮时,服务器不会退出while循环。为什么呢?

编辑:这是,如何在ViewController中启动服务器:

// called when the user clicks the start button
  - (IBAction) clickedStart
   {
   dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

    if (...) { // all needed data has been entered
        // start server here
        if(theServer == nil) {
            theServer = [[SNPTServer alloc] initWithHost:serverIP.text AndPort:    [serverPort.text intValue] AndViewController:self];
            dispatch_async(queue, theServer.myServer);
        }
    }

}

如你所见,我已经将构造函数改变了一点。

1 个答案:

答案 0 :(得分:2)

我的回答只有在你的while循环的主体看起来类似于以下内容时才有效(我会假设它)

while (blocksafeSelf.shouldRun) {
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                             beforeDate:[NSDate distantFuture]];
}

在这种情况下,仅将shouldRun设置为NO是不够的。 while循环在不同的线程/ runLoop上运行,因此必须发生一个事件导致运行循环弹出,以便再次检查条件。

最简单的方法是从运行服务器的线程中将shouldRun设置为NO。我会做这样的事情:

myServer = ^() {
    self.runThread = [NSThread currentThread]; // runThread declared elsewhere
    while (blocksafeSelf.shouldRun) {
          ....
        }
    }

然后当你想要取消它时:

- (IBAction) clickedStop
{
    if ([NSThread currentThread] == theServer.runThread) {
        if(theServer != nil) {
            theServer.shouldRun = NO;
        }
    } else if (theServer.runThread) {
        [self performSelector:_cmd
                     onThread:theServer.runThread
                   withObject:nil
                waitUntilDone:NO];
    }
}