2012-08-13 55 views
4

我試圖從id __autoreleasing *轉換爲CFTypeRef *(void **)。如何從id __autoreleasing *轉換爲無效的ARC在ARC?

我已經試過:

id __autoreleasing *arg = [OCMArg setTo:mockData]; 

CFTypeRef expectedResult = (__bridge CFTypeRef) *arg; 

[[[self.mockSecItemService expect] andReturnValue:OCMOCK_VALUE(mockCopyStatus)] copyItemMatching:queryCheck 
                          result:&expectedResult]; 

但是,代碼崩潰時自動釋放池排出。

在ARC環境中,如何將void **轉換爲void **?

+0

這是一個bad_access錯誤? – Dustin 2012-08-13 18:05:25

+0

你在發佈'expectedResult'嗎?如果這樣就停下來。 – Joe 2012-08-13 18:14:02

+0

我收到一個bad_access錯誤,但我沒有發佈expectedResult。 – Eric 2012-08-13 18:15:30

回答

3

我不知道你正在使用的API,所以我不能100%確定發生了什麼。我GOOGLE了,他們似乎是OCMock的一部分。我下載了它(並沒有安裝它,因爲我不感興趣),我迅速瀏覽了源代碼。

我在該代碼中看到一些非常可疑的東西。下面是他們如何實現你所說的第一種方法:

@implementation OCMArg 

.... 

+ (id *)setTo:(id)value 
{ 
    return (id *)[[[OCMPassByRefSetter alloc] initWithValue:value] autorelease]; 
} 

因此,他們正在返回的id*這實際上只是一個id。對我來說,要麼是廢話/錯誤,要麼是試圖操作ObjC內部(即使沒有記錄,ObjC對象存儲的第一件事實際上是指向對象類的指針,因此類型爲Class,它與id,因此它以某種方式有效地將指向對象的指針或指向對象的指針指向Class*id*)。我沒有時間或興趣去研究整個API,找出他們爲什麼這樣做。他們實際上可能有一個很好的理由(例如,如果你只將這個結果傳遞給另一個知道它應該是什麼的API,但你在這裏做的不止這些)。我不會學習OCMock,而是會盡我所能地解釋你所發生的事情(ObjC和ARC)。

id __autoreleasing *arg = [OCMArg setTo:mockData]; 

ARC在這行代碼中絕對不會做任何事情。

你可以在上面看到那種方法。類OCMPassByRefSetter是一個簡單的類,只保留它後保存參數,因此保留mockData。該OCMPassByRefSetter是自動釋放,並將在下一個消失(釋放mockData使*arg引用釋放的內存)。

注意arg其實指向OCMPassByRefSetter(該isaisa是任何對象的「第一」的伊娃,這是Class類型和指向對象的類的。但是,這是沒有證件,並可以在改變任何時候)。

CFTypeRef expectedResult = (__bridge CFTypeRef) *arg; 

*argid型這與CFTypeRef兼容的,所以鑄件是有效的。你使用__bridge,所以ARC絕對沒有。

如果arg指着一張「收費免費橋」 CF /可可類,這將是完全合法的代碼,但你必須要小心,expectedResult將在下屆漏失效(這不是retained,但它是活的一個自動發佈的實例)。

[[[self.mockSecItemService expect] andReturnValue:OCMOCK_VALUE(mockCopyStatus)] copyItemMatching:queryCheck 
                result:&expectedResult]; 

不知道這條線是幹什麼的。鑑於您在上面的評論中發佈的原型,ARC在部分result:&expectedResult上沒有做任何事情。

你說這是一個圍繞SecItemCopyMatching的包裝,但據我所知它不僅僅是這樣。如果它只是立即呼籲SecItemCopyMatching通過result:的論點,你很可能會搞砸了。但名字expectedResult和事實,這是OCMock讓我覺得這是比這更復雜一點。

你必須自己調查一下。但請記住:

  • 只要當前函數退出,您通過的參數(&expectedResult)將變爲無效,因爲它是局部變量。
  • 只要存在漏極,的值就會變爲無效,因爲該地址指向將由漏極重新分配的存儲器。
  • 任何東西與值expectedResult可能會出現非常錯誤的,因爲我不認爲Class合格爲「免費橋接」。

我懷疑,但我可能是非常錯誤的,你沒有使用OCMock apis的方式,他們打算使用。但在這方面,我無法幫助你,也許你確實做得對。

+0

我得出了一個類似的結論,而不是潛入OCMock的內部,我創建了一種處理轉換的新方法。我已經添加了該方法作爲答案。 – Eric 2012-08-14 00:32:53

+0

在OCMock中這種方法被這樣聲明的原因是它的返回類型需要與用於返回值的方法參數兼容, NSError **。該方法用於「流利」界面風格,以指定模擬應該將該參數設置爲某個值,例如,假設模擬用於存根NSURLConnection:[[connectionMock stub] sendSynchronousRequest:[OCMArg any] returningResponse:[OCMArg setTo:cannedResponse] error:[OCMArg setTo:someError]]; – 2012-08-16 14:11:01

0

與其試圖弄清楚如何將變量轉換爲正確的格式(OCMock在內部執行一些複雜的事情),我添加了另一種方法來處理轉換。

- (OSStatus)findItemMatching:(NSDictionary *)query result:(id __autoreleasing *)outResult { 
    NSAssert(outResult, @"outResult is required"); 

    CFTypeRef result = nil; 
    OSStatus status = [self copyItemMatching:query result:&result]; 

    if (result) { 
     *outResult = CFBridgingRelease(result); 
    } 

    return status; 
}