I saw an example of a long polling technique on pastebin and I wondered whether the recursive nature of the design would result in a stack overflow? Sorry if this is a noob question, but I'm unfamiliar with long-polling and I'm not super familiar with objective-c.
//long polling in objective-C
- (void) longPoll {
//create an autorelease pool for the thread
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
//compose the request
NSError* error = nil;
NSURLResponse* response = nil;
NSURL* requestUrl = [NSURL URLWithString:@"http://www.example.com/pollUrl"];
NSURLRequest* request = [NSURLRequest requestWithURL:requestUrl];
//send the request (will block until a response comes back)
NSData* responseData = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response error:&error];
//pass the response on to the handler
//(can also check for errors here, if you want)
[self performSelectorOnMainThread:@selector(dataReceived:)
withObject:responseData waitUntilDone:YES];
//clear the pool
[pool drain];
//send the next poll request
[self performSelectorInBackground:@selector(longPoll) withObject: nil];
}
- (void) startPoll {
//not covered in this example:
// -stopping the poll
// -ensuring that only 1 poll is active at any given time
[self performSelectorInBackground:@selector(longPoll) withObject: nil];
}
- (void) dataReceived: (NSData*) theData {
//process the response here
}
source for example: http://pastebin.com/3z5SM4R0
No, that code won't cause a stack overflow because each call isn't pushing a new stack frame on the current stack.
In C (and thus Objective-C), when you call a function, a "stack frame" is "pushed onto the stack". The stack frame contains data for the function call, like function arguments and a return address (among other things). That info takes space, so a maximum stack depth is enforced.
Every time a function is called, a stack frame is "pushed". Every time a function returns, a stack frame is "popped". To visualise the problem, see the following method:
- (void)overflow
{
NSLog(@"Pushing...");
[self overflow];
NSLog(@"Popping...");
}
That would print:
Pushing...
Pushing...
Pushing...
Pushing...
... (etc until overflow).
As you can see, the function never returns. Each time it recurses, it pushes another stack frame.
The difference in the example you posted is that the method doesn't call itself directly. It uses the performSelectorInBackground:withObject:
method, which doesn't immediately call the method. It schedules it on another thread¹ (with another call stack), then immediately returns. So, revisiting the previous example:
- (void)overflow
{
NSLog(@"Pushing...");
[self performSelectorInBackground:@selector(overflow) withObject:nil];
NSLog(@"Popping...");
}
That would now print:
Pushing...
Popping...
Pushing...
Popping...
Pushing...
Popping...
... (etc forever).
So you can see the second example keeps a balanced stack by scheduling recursion asynchronously, instead of calling it synchronously on its own thread.
¹According to the documentation