2013-07-08 73 views
1

我看到了一個關於pastebin的長輪詢技術的例子,我想知道設計的遞歸性質是否會導致堆棧溢出?對不起,如果這是一個noob的問題,但我不熟悉長輪詢,我不是非常熟悉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.mysite.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 
} 

來源例如: http://pastebin.com/3z5SM4R0

編輯: 如果這是形成不良的問題,值得一downvote的不好的事將有助於阻止我問在貧窮問題快速記事未來。否則,stackoverflow開始感覺像一個不友好的和獨家社區。

+1

它可能不是破壞堆棧,但男孩你好將它催生了大量的線程,這有時非常非常昂貴。 – CodaFi

+0

@CodaFi所以它會爲每次遞歸產生一個新線程? – David

+2

這是一個實現細節。我相信如果有機會,它可能會有,但希望他們變得更聰明並在GCD之上實施它。選擇器已經在後臺執行了,只是將它設置爲延遲並且它將繼續在同一個線程上調用。更好的是,將其重構爲NSOperation並創建一個私有隊列。您將能夠更輕鬆地調試任何故障。 – CodaFi

回答

5

不,該代碼不會導致堆棧溢出,因爲每個調用都不會在當前堆棧上推送新的堆棧幀。在C(以及Objective-C)中,當你調用一個函數時,一個「堆棧幀」被「壓入堆棧」。堆棧幀包含函數調用的數據,如函數參數和返回地址(等等)。該信息佔用空間,因此最大堆棧深度被強制執行。

每次調用一個函數時,都會「推送」一個堆棧幀。每次函數返回時,堆棧框架都會「彈出」。以可視化的問題,請參見下面的方法:

- (void)overflow 
{ 
    NSLog(@"Pushing..."); 
    [self overflow]; 
    NSLog(@"Popping..."); 
} 

這將打印:

Pushing... 
Pushing... 
Pushing... 
Pushing... 
... (etc until overflow). 

正如你可以看到,該函數永遠不會返回。每次它遞歸時,它會推送另一個堆棧幀。

您發佈的示例中的差異是該方法不會直接調用它自己。它使用performSelectorInBackground:withObject:方法,該方法不會立即調用該方法。它在另一個線程¹(使用另一個調用堆棧)上安排它,然後立即返回。因此,重新審視前面的例子:

- (void)overflow 
{ 
    NSLog(@"Pushing..."); 
    [self performSelectorInBackground:@selector(overflow) withObject:nil]; 
    NSLog(@"Popping..."); 
} 

這將現在的打印:

Pushing... 
Popping... 
Pushing... 
Popping... 
Pushing... 
Popping... 
... (etc forever). 

所以你可以看到第二個例子不斷通過調度遞歸均衡棧異步,與其說這是同步於自己的線。


¹According到documentation

+1

這有點讓人困惑,但我想我明白你在說什麼。因此,所有這些NS對象不會被放在堆棧上,而'[self performSelectorInBackground:@selector(longPoll)withObject:nil];'被調用? – David

+1

不完全。這些對象全部分配在堆上,並且不會影響堆棧大小。我更新了更多的細節。 –

+1

感謝您的詳細解釋,馬特! – David