2016-12-29 42 views
1

成爲NULL我有C++編寫的圖書館借了一些事件,在後臺線程的工作原理:爲什麼某個變量塊

virtual void OnData(const char* data) 
{ 
    NSLog(@"Here 'data' string is present %s", data); 
    @autoreleasepool { 
     NSString* sData= [NSString stringWithCString:data encoding:NSUTF8StringEncoding]; 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      NSLog(@"Here _sometimes_ 'data'(%s) is nil (\0). But sData is always present %@", data, sData); 
      [callback OnData:sData]; 
     }); 
    }; 
} 

而且有時我有NULL(我懷疑它實際上是垃圾)在參數dispatch_async塊變量。但是本地的NSString變量總是在這裏。爲什麼?

P.S.在這種情況下,我真的必須使用@autoreleasepool嗎?

+2

這不是C++。 – Barmar

+0

Objective-C與C++混合 – BugaBuga

回答

3

對於在執行異步塊時指向的緩衝區的生命週期,您無法保證。 data可能是懸掛指針的那一點(並應該假定是這樣)。在任何異步引用或最初創建的上下文之外使用C風格指針是非常危險的。

您應該使用內存管理對象(如NSDataNSString等),或者,如果你堅持使用C風格的指針和需要在異步塊引用這個指針,將數據複製到自己的緩衝區,使用該緩衝區,然後在完成異步例程中的緩衝區時釋放它。在這種情況下,你有你的sData,所以在那之後不要再提及data,你會沒事的。


P.S.您稍後會問在這種情況下您是否必須使用@autoreleasepool

總之,在大多數情況下,不需要額外的自動釋放池。值得注意的是,當使用Grand Central Dispatch(例如dispatch_async)時,它有自己的autorelease池,所以你不必創建一個。而且,當你的主線程退回到它的運行循環時,它又會被清除。簡而言之,您只需在實例化自己的NSThread對象時手動創建自動釋放池。

話雖如此,如果在回退到運行循環之前進行大量的內存密集型操作,有時您會引入autorelease池。在這種情況下,您將添加自動釋放池,以減少應用程序的峯值內存使用量。但這似乎並不是這些情況之一。

1

如果你有這樣的事情:

void CallOnData() 
{ 
    char *test = malloc(5 * sizeof(char)); 
    strcpy(test, "test"); 
    OnData(test); 
    free(test); 
} 

您應該預期數據是在塊「NULL」。

並且不需要autorelease,假設您使用的是ARC,您應該是。

+0

爲什麼'autoreleasepool'不需要?它從新線程調用,不使用'autoreleasepool'創建。 – BugaBuga

+1

這個答案在OSX 10.9,iOS 7和更新的版本中提供了一些有關NSThread和autoreleasepool的信息。 http://stackoverflow.com/a/30519746/16524 – Fostah