How to verify number of method calls using OCMock - iphone

Is there a way to verify that a method has been called 'x' amount of times?

Looking at the test file for OCMock, it seems that you need to have the same number of expects as you have calls. So if you call someMethod three times, you need to do...
[[mock expect] someMethod];
[[mock expect] someMethod];
[[mock expect] someMethod];
...test code...
[mock verify];
This seems ugly though, maybe you can put them in a loop?

I've had success by leveraging the ability to delegate to a block:
OCMStub([mock someMethod]).andDo(^(NSInvocation *invocation)
{ /* block that handles the method invocation */ });
Inside the block, I just increment a callCount variable, and then assert that it matches the expected number of calls. For example:
- (void)testDoingSomething_shouldCallSomeMethodTwice {
id mock = OCMClassMock([MyClass class]);
__block int callCount = 0;
OCMStub([mock someMethod]).andDo(^(NSInvocation *invocation) {
++callCount;
});
// ...exercise code...
int expectedNumberOfCalls = 2;
XCTAssertEqual(callCount, expectedNumberOfCalls);
}
The block should be invoked each time someMethod is called, so callCount should always be the same as the number of times the method was actually called.

If you need to check if a method is only called once, you can do it like this
[self.subject doSomething];
OCMVerify([self.mock method]);
OCMReject([self.mock method]);
[self.subject doSomething];

Related

Creating the loop using GCD

So here is what I've got:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1*NSEC_PER_SEC), dispatch_get_current_queue(), ^{
bool ready = some_function();
if( ready ) {
do_smth_here()
} else {
//invoke this block one more time after 0.1 sec
}
});
The problem is how can I get the reference to the current block?
Instead of jumping through the hoops shown above, I typically declare an instance method that I can call that, internally, takes care of the retriggers as necessary. That way, any given block is one-shot, but the re-trigger creates a new block.
As long as the block creation isn't terribly expensive -- which it won't be if the state is coming from whatever encapsulates the instance method -- it is efficient enough and a heck of a lot simpler.
- (void) retriggerMethod
{
... do stuff here, assuming you want to do it on first invocation ...
dispatch_after( ..., ^{
[self retriggerMethod];
});
}
You can restructure it as needed. And you can easily add a BOOL instance variable if you want to protect against simultaneous retriggers, etc...
This also provides a convenient hook for canceling; just add a BOOL to the instance that indicates whether the next invocation should really do anything and re-schedule.
Jeffrey Thomas's answer is close, but under ARC, it leaks the block, and without ARC, it crashes.
Without ARC, a __block variable doesn't retain what it references. Blocks are created on the stack. So the callback variable points to a block on the stack. When you pass callback to dispatch_after the first time (outside of the block), dispatch_after successfully makes a copy of the block on the heap. But when that copy is invoked, and passes callback to dispatch_after again, callback is a dangling pointer (to the now-destroyed block on the stack), and dispatch_after will (usually) crash.
With ARC, a __block variable of block type (like callback) automatically copies the block to the heap. So you don't get the crash. But with ARC, a __block variable retains the object (or block) it references. This results in a retain cycle: the block references itself. Xcode will show you a warning on the recursive dispatch_after call: “Capturing 'callback' strongly in this block is likely to lead to a retain cycle”.
To fix these problems, you can copy the block explicitly (to move it from the stack to the heap under MRC) and set callback to nil (under ARC) or release it (under MRC) to prevent leaking it:
__block void (^callback)() = [^{
if(stop_) {
NSLog(#"all done");
#if __has_feature(objc_arc)
callback = nil; // break retain cycle
#else
[callback release];
#endif
} else {
NSLog(#"still going");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
}
} copy];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
Obviously you can drop the #if and just use the branch appropriate for your memory management.
I think this is the code your looking for:
__block void (^callback)();
callback = ^{
bool ready = some_function();
if( ready ) {
do_smth_here()
} else {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
}
};
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
Thanks to ^ Blocks Tips & Tricks

create a method with return using a delay

working on xcode I realized that if I create a non-void method, I call it from a class / method, the result is processed optimally only if the action is immediate. I tried to do a test by inserting a delay and I realized that it no longer works.
I will write down here the example that I created:
Class A
//--------------------CLASS A
- (void)viewDidLoad {
[super viewDidLoad];
i = 0;
Class *classB = [[Class alloc] init];
i = [classB method1];
[self performSelector:#selector(method3) withObject:NULL afterDelay:1.8];
}
-(void)method3 {
NSLog(#"i = %i",i); // i = 0
}
Class B
//--------------------CLASS B
-(int)method1 {
[self performSelector:#selector(method2) withObject:NULL afterDelay:1];
return a;
}
-(void)method2 {
a = 800;
}
Obviously my problem is not something so trivial but I tried to make it easy to get an answer as thoroughly as possible, I was advised to use modal methods but I don't think that's the solution I was looking for.
What could I do to solve this?!
What you really need is a better understanding of asynchronous methods. In your method1, the variable a is never altered -- all you are doing is scheduling method2 to be called in the future and then returning the current state of variable a.
In Objective-C, there are a few different ways you can solve this problem. People most commonly use protocols and delegates to solve this issue. Here is a basic intro to protocols and delegates. Basically, you would want your class A object to be a delegate of your class B object. You could also use NSNotifications or blocks, although you should probably understand the usage of protocols and delegates (they are very important in Objective-C) before moving on to notifications and blocks.
What could I do to solve this?!
Where do you want to return the value to? In your example, method1 will complete long before method2 is ever invoked. If you want to preserve the value calculated by method2, you'll typically have that method store the value in one of ClassB's instance variables and possibly call some other method to continue processing.
If you really need method1 to return the result from method2, you'll need to call it synchronously (i.e. without -performSelector:withObject:afterDelay:). In this case, consider a) why you need the delay at all; and b) if you should perhaps be calling method1 after a delay instead of method2.
We'll be able to provide much better help if you can explain what the real-world problem that you're trying to solve is.

Threads from GCD reading old value

My problem is that I'm using dispatch_async(dispatch_get_main_queue(), ^(void) { ... }); to call a method asynchronously, in this method depending on some conditions i set a boolean to YES. When this boolean is read in this method, it's always read by it's old value which is NO.
The weird thing is that when i made a breakpoint on the line where the bool is checked, everything went fine and as intended !
EDIT:
Here is the code where the threads are spawned
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self drawFaceBoxesForFeatures:features forVideoBox:claporientation:curDeviceOrientation image:img];
});
The method itself
- (void)drawFaceBoxesForFeatures:(NSArray *)features forVideoBox:(CGRect)clap orientation: (UIDeviceOrientation)orientation image:(UIImage *)image;
{
if (![self getSendingRequestStatus]) {
NSLog(#"Sending req");
// send async request
dispatch_async(dispatch_get_main_queue(),^ {
sendingRequest = YES;
} );
}
}
It looks like you are modifying an ivar that was created outside of a block inside of the block. In order to do this and have the ivar hold the correct value, you are going to need to use the __block keyword like so:
#interface MyCoolClass : NSObject {
#private
__block int sendingRequest_;
}
As Jack Lawrence said in the commend above, "[the runtime] takes a snapshot of all of the relevant objects/variables at that point in time". The __block identifier will tell the runtime that it should not copy that ivar to the heap and will allow you to assign values to sendingRequest_ inside of a block, even if that block is simply being run on the main thread.
A lot of good information to start with (including the above) can be found in the Blocks Programming Guide.
When primitives are passed into a block they are copied. So if you put a primitive local or instance variable in a block and then later change it either in the same method that created the block (after the block creation) or another method it won't have any effect on the variable in the block. In the case of a local variable, just make sure you make any necessary changes before block creation. In the case of instance variables you could try accessing the instance variable by using some C: self->iVar or declare it as a property and access it through the property accessor: self.iVar.

Passing blocks for methods

I would like to pass in different blocks into a method. The method would subsequently use the passed in block as parameter to dispatch_async.
I have my block declared like this:
typedef int (^ComputationBlock)(int);
The class method that accepts the block is implemented as:
- (void)doSomething:(int)limit withBlock:(ComputationBlock)block;
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// typical in-lined block for dispatch_async:
dispatch_async(queue, ^{
// do some work here
});
// I want to pass in the block as the 2nd parameter to dispatch_async
// but the compiler will warn me of a type mismatch unless I cast
// the block like:
dispatch_async(queue, (dispatch_block_t)block);
}
#end
Is it okay to typecast the 'block' parameter as dispatch_block_t?
No, that's not cool to do -- the block passed to dispatch_async needs to take no parameters and return nothing. Casting your ComputationBlock to that would be a Bad Idea (it's not nice to fool mother nature).
Simply wrap your block that you want to call inside one of the right type:
dispatch_async(queue, ^{ block(0); } );
(note that you also need to supply a parameter to your ComputationBlock when you invoke it.)
It may compile, but it won't work. dispatch_block_t blocks must not take any arguments and must not have a return value.
Pass value using __block
__block int backValue;
it can modify in block

Objective-C performSelector does not call a method with parameter

I'm having a problem with performSelector. It works if I call a method without parameters, but it doesn't even call the method if I pass a parameter.
Example:
- (void)test
{
NSLog(#"test"); //it works!!
}
...
[self performSelector:#selector(test) withObject:nil afterDelay:1.0];
- (void)switchOn:(NSNumber *) index
{
NSLog(#"switchOn"); //it doesn't work :-(
}
....
NSLog(#"int is %d", [((NSNumber *)obj) intValue]); //print the correct value
[self performSelector:#selector(switchOn:) withObject:obj afterDelay:1.0];
I get no errors neither. Where could it be the problem?
thanks
What is the type of the parameter for the switchOn: selector?
It must be of type id otherwise performSelector:WithObject: won't work. To quote the docs:
aSelector should identify a method that takes a single argument of type id. For methods with other argument types and return values, use NSInvocation.
performSelectorWithObject: sends a message to the selector with the object you supplied as the first argument. The receiving method must accept a single parameter of type id. For anything else use NSInvocation.
You might want to check out a similar question about this.
Try to use:
- (void)switchOn:(id)index