EXC_BAD_ACCESS在访问OCMock的andDo参数时

我正在尝试使用OCMock的stub和Do方法编写一段代码。

在这种情况下,正在testingUIImageView扩展类。 我想检查扩展调用[self setImage:]参数是非零(稍后将使用其他图像比较)。

在使用OCMock的andDo方法时,在块完成后,testing会使用EXC_BAD_ACCESS进行崩溃。

id mockView = [OCMockObject mockForClass:[UIImageView class]]; [[[mockView stub] andDo:^(NSInvocation *invocation) { UIImage *img; [invocation getArgument:&img atIndex:2]; <---- line causing the exception somebodySetImage |= (img != nil); }] setImage:OCMOCK_ANY]; [mockView do_something_that_calls_setImage]; 

我现在发现的唯一解决scheme是使用andCall而不是andDo ,但这使testing变得复杂。

我可以用andDo避免崩溃吗?

更新那么,我将尝试在这里给出一个更好的例子:这是testing代码的新部分:

 - (void)testDownloadingThumbnail { PInfo *_sut = [[PInfo alloc] init]; __block id target = nil; id mock = [OCMockObject mockForClass:[NSOperationQueue class]]; [[[mock expect] andDo:^(NSInvocation *inv) { NSInvocationOperation *op; [inv getArgument:&op atIndex:2]; target = [[op invocation] target]; /* replacing this line with STAssert does not help either */ }] addOperation:OCMOCK_ANY]; [_sut setDownloadQueue:mock]; [_sut startDownloadingImagesAsync:YES]; [mock verify]; STAssertEqualObjects(target, _sut, @"invalid op target"); } 

这里是testing代码(来自PInfo的单一方法):

 - (void)startDownloadingImagesAsync:(bool)isThumbnailImg { NSInvocationOperation *inv; inv = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadThumbnailWorker:) object:nil]; [[self downloadQueue] addOperation:inv]; } 

使用EXC_BAD_ACCESS从startDownloadingImagesAsync退出时,代码仍然崩溃。 如果在andDo块中添加一个断点,我会看到控件到达了这个点,并通过getArgument获取了正确的对象。

然而,如果我在块中使用getArgument ,它会崩溃无论我尝试做什么。

PS感谢您的帮助。

在使用NSProxy的forwardInvocation:方法时遇到了类似的问题。

你可以试试下面吗?

 NSInvocationOperation *op; // Change this line __unsafe_unretained NSInvocationOperation *op; // to this line 

或者另一种方法可能是保留NSInvocation的论点:

 [invocation retainArguments]; 

http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSInvocation_Class/Reference/Reference.html#//apple_ref/occ/instm/NSInvocation/retainArguments

稍后我会尝试添加更详细的解释。

我认为问题是你正试图直接调用一个模拟对象。 对于你想要做的,你不应该需要一个模拟对象。 只需调用该方法并validation图像是否已设置:

 expect(myObject.imageView.image).to.beNil(); [myObject do_something_that_calls_setImage]; expect(myObject.imageView.image).not.to.beNil(); 

如果你真的想使用模拟出于某种原因,你可以做一个真正的UIImageView和部分模拟:

 UIImageView *imageView = myObject.imageView; id mockView = [OCMockObject partialMockForObject:imageView]; __block BOOL imageSet = NO; [[[mockView stub] andDo:^(NSInvocation *invocation) { UIImage *img; [invocation getArgument:&img atIndex:2]; imageSet = (img != nil); }] setImage:OCMOCK_ANY]; [myObject do_something_that_calls_setImage]; expect(imageSet).to.beTruthy(); 

在我的情况下,这是因为我给这个方法引入了另一个参数,所以块参数被移动了一个。

我通过将[inv getArgument:&op atIndex:2]更改为[inv getArgument:&op atIndex:3]