4

我正在尝试从 id __autoreleasing * 转换为 CFTypeRef * (void **)。

我试过了:

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

CFTypeRef expectedResult = (__bridge CFTypeRef) *arg;

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

但是当自动释放池耗尽时,代码会崩溃。

在 ARC 环境中如何转换为 void**?

4

2 回答 2

3

我不知道您正在使用的 API,所以我不能 100% 确定发生了什么。我用谷歌搜索,他们似乎是 OCMock 的一部分。我下载了它并且(因为我不感兴趣而没有安装它)我迅速浏览了源代码。

我在该代码中看到了一些非常可疑的东西。以下是他们如何实现您调用的第一个方法:

@implementation OCMArg

....

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

所以他们正在返回一个id*实际上只是一个id.

对我来说,这要么是胡说八道/错误,要么是试图操纵 ObjC 内部(即使没有记录,ObjC 对象存储的第一件事实际上是指向对象类的指针,因此它的类型Class与 兼容id,因此它在某种程度上是有效地将指向对象的指针或指向对象的指针转换idClass*id*)。我没有时间或兴趣去研究整个 API 来弄清楚他们为什么这样做。他们实际上可能有一个很好的理由(例如,如果您只将该结果传递给另一个知道它应该是什么的 API,但您在这里做的还不止这些)。我不会研究 OCMock,而是会尽力向您解释正在发生的事情(ObjC 和 ARC)。

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

ARC 在这行代码中绝对不会做任何事情。

您可以在上面看到该方法的作用。类OCMPassByRefSetter是一个简单的类,它只是在保留它之后存储参数,所以mockData被保留。是自动释放的,并将OCMPassByRefSetter在下一次耗尽时消失(释放mockData *arg引用已释放的内存)。

请注意,arg实际上指向isaOCMPassByRefSetter(这isa是任何对象的“第一个”ivar,它是类型Class并指向对象的类。但这没有记录,并且可能随时更改)。

CFTypeRef expectedResult = (__bridge CFTypeRef) *arg;

*argid是与兼容的类型CFTypeRef,因此强制转换是有效的。你使用__bridge所以 ARC 绝对什么都不做。

如果arg指向“免费桥接”CF/Cocoa 类,这将是完全有效的代码,但您必须小心,它expectedResult会在下一次耗尽时变为无效(它不是retained,但它作为自动释放实例存在)。

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

不知道这条线是做什么的。鉴于您在上面的评论中发布的原型,ARC 对此没有任何作用result:&expectedResult

你说它是一个包装器SecItemCopyMatching,但据我所知,它不止于此。如果它只是立即调用SecItemCopyMatching它作为result:参数,你可能会把事情搞砸。但是这个名字expectedResult和 OCMock 的事实让我觉得这比这更复杂一些。

你必须自己调查一下。但要记住:

  • 一旦当前函数退出,您传递的参数 ( &expectedResult) 将变得无效,因为它是一个局部变量。
  • 一旦有排水管, 的值就会expectedResult变得无效,因为该地址指向将被排水管释放的内存。
  • 任何具有价值的事情expectedResult都可能会出错,因为我认为 a 不Class符合“免费桥接”的条件。

我怀疑,但我可能错了,您没有按照预期的方式使用 OCMock api。但在这方面我无法帮助你,也许你实际上做得对。

于 2012-08-13T23:59:01.233 回答
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;
}
于 2012-08-14T00:32:08.017 回答