我不知道您正在使用的 API,所以我不能 100% 确定发生了什么。我用谷歌搜索,他们似乎是 OCMock 的一部分。我下载了它并且(因为我不感兴趣而没有安装它)我迅速浏览了源代码。
我在该代码中看到了一些非常可疑的东西。以下是他们如何实现您调用的第一个方法:
@implementation OCMArg
....
+ (id *)setTo:(id)value
{
return (id *)[[[OCMPassByRefSetter alloc] initWithValue:value] autorelease];
}
所以他们正在返回一个id*
实际上只是一个id
.
对我来说,这要么是胡说八道/错误,要么是试图操纵 ObjC 内部(即使没有记录,ObjC 对象存储的第一件事实际上是指向对象类的指针,因此它的类型Class
与 兼容id
,因此它在某种程度上是有效地将指向对象的指针或指向对象的指针转换id
为Class*
或id*
)。我没有时间或兴趣去研究整个 API 来弄清楚他们为什么这样做。他们实际上可能有一个很好的理由(例如,如果您只将该结果传递给另一个知道它应该是什么的 API,但您在这里做的还不止这些)。我不会研究 OCMock,而是会尽力向您解释正在发生的事情(ObjC 和 ARC)。
id __autoreleasing *arg = [OCMArg setTo:mockData];
ARC 在这行代码中绝对不会做任何事情。
您可以在上面看到该方法的作用。类OCMPassByRefSetter
是一个简单的类,它只是在保留它之后存储参数,所以mockData
被保留。是自动释放的,并将OCMPassByRefSetter
在下一次耗尽时消失(释放mockData
并*arg
引用已释放的内存)。
请注意,arg
实际上指向isa
的OCMPassByRefSetter
(这isa
是任何对象的“第一个”ivar,它是类型Class
并指向对象的类。但这没有记录,并且可能随时更改)。
CFTypeRef expectedResult = (__bridge CFTypeRef) *arg;
*arg
id
是与兼容的类型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。但在这方面我无法帮助你,也许你实际上做得对。