2012-08-13 67 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; 
}