0

ここでいくつか質問した後、私は次のようなサーバーを実行することにしました。

@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ができました。これは、サーバーをプロパティとして持ち、その実装に次のメソッドがあります。

// 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);
        }
    }

}

ご覧のとおり、コンストラクターを少し上に変更しました。

4

1 に答える 1

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];
    }
}
于 2012-11-15T22:11:14.543 に答える