测试多代理回调方法时OCMVerify在mock回调执行后崩溃
崩溃根因
- 主因:你在
andDo的回调中从NSInvocation取出block参数时,没有手动执行copy操作。block作为方法参数传递时默认存储在栈区,NSInvocation不会自动对block类型参数做内存管理,你拿到的指针指向的栈内存在fetchInt:方法返回后就会被回收,此时再调用block就会触发EXEC_BAD_ACCESS野指针崩溃。 - 次因:检查你的测试代码中
_mockedDelegate是否已正确初始化,若为未初始化的野指针,后续调用delegateDoStuff方法时也会触发相同崩溃。
修复方案
在从NSInvocation读取block后立刻调用copy方法,将栈block复制到堆上,保证调用时内存有效。修复后的测试代码如下:
- (void) testWithMultipleCallbacks { // 若之前未初始化_mockedDelegate,需补充初始化逻辑 if (!_mockedDelegate) { _mockedDelegate = OCMProtocolMock(@protocol(MyDelegate)); } id <MyDelegateWithCallback> mockDelegateWithCallback = OCMProtocolMock(@protocol(MyDelegateWithCallback)); OCMStub([mockDelegateWithCallback fetchInt:[OCMArg any]]).andDo(^(NSInvocation *invocation) { void (^block)(int) = NULL; [invocation getArgument:&block atIndex:2]; // 新增copy操作,将栈block转移到堆内存 block = [block copy]; NSLog(@"got here"); block(33); }); [_classUnderTest methodWithMultipleCallbacks: _mockedDelegate withSecondDelegate: mockDelegateWithCallback]; // 可直接校验参数为32,提升测试准确性 OCMVerify(OCMTimes(1), [_mockedDelegate delegateDoStuff:32]); }
额外优化建议
如果你的业务代码中fetchInt:是异步执行回调的场景,还需要在业务代码中将传入的callback block copy到堆上,避免业务代码运行时出现同样的野指针问题。
内容的提问来源于stack exchange,提问作者hao chen
相关产品推荐
相关产品推荐

