2012-05-24 51 views
2

情況:是NSGarbageCollector的disableCollectorForPointer:由enableCollectorForPointer平衡電話:電話?

我需要一個Objective-C對象傳遞給一個異步C API如後面將要傳遞給回調函數I提供不透明參考(void*)。回調然後調用對象上的方法。該代碼需要在存在垃圾回收的情況下工作,並且在我調用C API和回調被它調用的時間之間,該對象不得GC'd。

NSGarbageCollector類提供disableCollectorForPointer:enableCollectorForPointer:方法標記和取消標記對象爲不可收集的根。

問:

我無法從文檔編制和Web搜索是,如果到disableCollectorForPointer:調用進行計數,必須由相同數量的enableCollectorForPointer:電話進行平衡。如果這是的情況和每個對象是標記爲根或沒有,調用我的回調enableCollectorForPointer:可以清除一些其他的代碼的現有根標誌,使物體進行收集,即使它不應該!

我見過的選擇是使用CFRetainCFRelease - 這些都是安全的,我自己NSObject子類使用?我以前只在免費橋接的CF對象上使用過這些功能。

積分爲它提供證據的答案。我看到disableCollectorForPointer:推薦到處都沒有提到這個安全方面。

注:

  • 我要支持垃圾收集該代碼將由PrefPane的系統偏好設置中使用。 PrefPane 的64位版本必須使用垃圾回收。所以使用ARC或手動refcounting不是一種選擇。
  • 的C API是蘋果公司(由於IOKit)中的一個,所以我有沒有對其進行控制無論是。

回答

1

我想我已經找到了答案。垃圾收集器的源代碼似乎並不可用,但頭文件中聲明爲NSGarbageCollectorNSGarbageCollector.hFoundation.framework接口包含以下內容:

// references outside the heap, globals, and the stack, e.g. unscanned memory, malloc memory, must be tracked by the collector 
- (void)disableCollectorForPointer:(void *)ptr;  // this pointer will not be collected... 
- (void)enableCollectorForPointer:(void *)ptr;  // ...until this (stacking) call is made 

注意「堆積」評論 - 我猜這意味着電話確實被計算在內?更多證據仍然歡迎!

更新:

只是可以很確定,我決定用一個小的測試程序(gcbridgetest來測試我的假設。米):

#import <Foundation/Foundation.h> 

@interface PJGarbageCollectionTest : NSObject 
@end 

@implementation PJGarbageCollectionTest 

- (id)init 
{ 
    self = [super init]; 
    if (!self) return nil; 
    NSLog(@"%@ -init", self); 
    return self; 
} 

- (void)finalize 
{ 
    NSLog(@"%@ -finalize", self); 
    [super finalize]; 
} 

@end 

static void* ext_ptr1 = NULL; 
static void* ext_ptr2 = NULL; 

static void create() 
{ 
    PJGarbageCollectionTest* test = [[PJGarbageCollectionTest alloc] init]; 
    [[NSGarbageCollector defaultCollector] disableCollectorForPointer:test]; 
    ext_ptr1 = test; 
    [[NSGarbageCollector defaultCollector] disableCollectorForPointer:test]; 
    ext_ptr2 = test; 
} 

static void killref(void** ext_ptr) 
{ 
    [[NSGarbageCollector defaultCollector] enableCollectorForPointer:*ext_ptr]; 
    *ext_ptr = NULL; 
} 


int main() 
{ 
    NSLog(@"collector: %@", [NSGarbageCollector defaultCollector]); 
    create(); 
    NSLog(@"Collecting with 2 external references"); 
    [[NSGarbageCollector defaultCollector] collectExhaustively]; 
    killref(&ext_ptr1); 
    NSLog(@"Collecting with 1 external reference"); 
    [[NSGarbageCollector defaultCollector] collectExhaustively]; 
    killref(&ext_ptr2); 
    NSLog(@"Collecting with 0 external references"); 
    [[NSGarbageCollector defaultCollector] collectExhaustively]; 
    return 0; 
} 

編譯時gcc -fobjc-gc-only -g -Wall -Wextra -ObjC gcbridgetest.m -framework Foundation -o gcbridgetest和運行爲./gcbridgetest,它提供了以下的輸出,確認啓用/ disableCollectorForPointer:呼叫確實計數:

2012-06-12 16:08:08.278 gcbridgetest[29712:903] collector: <NSGarbageCollector: 0x20000f420> 
2012-06-12 16:08:08.281 gcbridgetest[29712:903] <PJGarbageCollectionTest: 0x20000ee60> -init 
2012-06-12 16:08:08.284 gcbridgetest[29712:903] Collecting with 2 external references 
2012-06-12 16:08:08.285 gcbridgetest[29712:903] Collecting with 1 external reference 
2012-06-12 16:08:08.286 gcbridgetest[29712:903] Collecting with 0 external references 
2012-06-12 16:08:08.286 gcbridgetest[29712:903] <PJGarbageCollectionTest: 0x20000ee60> -finalize