Search code examples
iosobjective-cnsurlconnectiongrand-central-dispatchlong-polling

Stopping an infinite while loop inside dispatch_async from another View Controller


I'm building a simple chatroom app in which i have an NSURLConnection sendSynchronousRequest: sending requests to a server a la Long Polling. I want to show a stream that consistently updates the chat feed to my users whilst running in the background.

My app also allows users to change their chatroom, whereby i need to close one NSURLConnection and open another for the respective feed.

My current implementation is as follows:

//in ViewController.m

dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_async(concurrentQueue, ^{
            while (longPollBOOL){
            NSArray *MSG = [self.currentChatFeed longPoll]; //infinitely call longPoll method
                dispatch_sync(dispatch_get_main_queue(), ^{
                    if (MSG.count != 0) //if the longPoll method returns a non-empty array, stick it into the message feed on the device.
                    {
                        for (id element in MSG)
                        {
                            [self.messages addObject:element];
                            [self finishReceivingMessage];
                        }
                    }
                });
            }

        });

I'm trying to kill the while loop by setting my BOOL = NO, but it's not working. That BOOL = NO is being sent by another View Controller in the app. I want to guarantee that this loop is halted before beginning another infinite loop for another chat room.

I want to kill this long Poll process for one given Chat Room before i start another Long Polling Process. Any IDeas?

Am i doing this correctly?


Solution

  • If you want a cancellable task you might be better of modelling it with NSOperations. You can easily do this without subclassing:

    NSBlockOperation *blockOperation = [[NSBlockOperation alloc] init];
    
    __weak __typeof(blockOperation) weakBlockOperation = blockOperation;
    
    [blockOperation addExecutionBlock:^{
      while (!weakBlockOperation.isCancelled) {
        NSArray *MSG = [self.currentChatFeed longPoll]; //infinitely call longPoll method
        dispatch_sync(dispatch_get_main_queue(), ^{
          if (MSG.count > 0) {
            for (id element in MSG) {
              [self.messages addObject:element];
              [self finishReceivingMessage];
            }
          }
        });
      }
    }];
    
    [queue addOperation:blockOperation];
    

    Than you just need to hold onto a reference to your operation and you can cancel it at any time.