How to check method caller source in Objective-C? - ios

I have a method which calls itself:
-(void)myMethod
{
//do stuff
[self myMethod];
//do stuff
}
I need to check, from inside myMethod where it is being called from. For example, IF called myMethod do this, ELSE do this.

Can you just pass in a boolean to show called from external vs called from recursion?
-(void)myMethod:(bool)externalCall
{
//do stuff
[self myMethod:false];
//do stuff
}
And then call that from outside with:
[self myMethod:true];
That may be over simplifying, especially if you need to get the calling method from multiple different locations (instead of recursion vs external call), but it seems to me the simplest answer to your presented problem.

Related

OCMockito - Verify order of method invocations

As far as I can see, there is no way to verify the order of method invocations on a mock.
Or am I missing something?
- (void)testResetCameraState_resetsCameraView
{
// Arrange
[given([_cameraManagerMock previewLayer]) willReturn:_testLayer];
// Act
[_cameraInteractor resetCameraState];
// Assert
[verifyCount(_cameraViewMock, times(1)) resetPreview];
[verifyCount(_cameraViewMock, times(1)) setPreviewLayer:_testLayer];
}
In this case you cannot verify, that the setPreviewLayer: is called after resetPreview.
I think I found a solution.
It's based on the givenVoid method added in this pull request:
https://github.com/jonreid/OCMockito/pull/93
Sadly it is not merged yet, so you need to download and build this version by yourself:
https://github.com/lysannschlegel/OCMockito/tree/given_void
With the new method you can verify the order of method calls in the following way:
- (void)testResetCameraState_resetsCameraView
{
// Arrange
[given([_cameraManagerMock previewLayer]) willReturn:_testLayer];
[givenVoid([self->_cameraViewMock resetPreview]) willDo:^id (NSInvocation *invocation)
{
[(MKTBaseMockObject*)self->_cameraViewMock reset];
return nil;
}];
// Act
[_cameraInteractor resetCameraState];
// Assert
[verifyCount(_cameraViewMock, never()) resetPreview];
[verifyCount(_cameraViewMock, times(1)) setPreviewLayer:_testLayer];
}
This will reset the mock after the first call of resetPreview.
So we can verify stuff after that call:
resetPreview is never called after the first call.
setPreviewLayer is called after resetPreview.
The reset call also resets the givenVoid() willDo: so a second reset call wouldn't reset the mock again.
Hope this helps, happy coding :D

Methods that use completion blocks and return an object

I have a method that inits the object and it has a completion block: typedef void(^initCompletionHandler)(BOOL succesful);
In this method I want to call the handler but I am not sure how to do it because if I call it before the return the object won't be finished initialising which is used immediately in the next line. I also obviously can't call the handler after the return. i,e:
if(haveError){
handler(NO);
}
else{
handler(YES);
}
return self;
Is there any way I can return and call the handler at the same time?
A couple of observations:
I'm unclear as to why you say "because ... the return object won't be finished initialising." You're doing the initialization, so just ensure it finishes all of the associated initialization before calling that handler. If the issue is that the caller won't have a valid reference to that object yet, you could always include a reference to it in the parameter of the block, e.g.
typedef void(^initCompletionHandler)(MyObject object, BOOL succesful);
and then supply that parameter, e.g.:
if (haveError){
handler(self, NO);
} else {
handler(self, YES);
}
Also, you say "I obviously can't call the handler after the return". But you can. You could just do a dispatch_async, if you wanted:
dispatch_async(dispatch_get_main_queue(), ^{
if (haveError){
handler(NO);
} else {
handler(YES);
}
});
return self;
That's a little inelegant, as if you call it from another thread, you have some potential race conditions that you might have to coordinate/synchronize, but you get the idea: You don't have to call the handler synchronously.
Having made both of those observations, I must confess that I'm not a fan of having init actually launching some asynchronous process and having its own completion block. I'd be inclined to make those two different steps. If you look at the Cocoa API, Apple has largely shifted away from this pattern themselves, generally having one method for instantiation, and another for starting the asynchronous process.

Not sure on method name of block code

I want to create a method which run's a user's provided block of code, making use of dispatch groups, and has the implementation as follows:
dispatch_group_enter(self.group);
block(^ {
dispatch_group_leave(self.group);
if (completion) {
completion();
}
});
dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);
I'm not sure how to write the name of this method, however.
It'd be something similar to:
- (void)performBlock:(void(^)())block;
But then remember that the block provided has to have its own callback for completion.
The implementation would be something like this:
[object performBlock:^(void(^)() completion) {
//Do stuff
completion();
}];
Have I misunderstood the question if I suggest?
- (void)performBlock:(void(^)())block completion:(void(^)())completion;
If I have not misunderstood I would recommend to add support for error handling
- (void)performBlock:(void(^)())block completion:(void(^)(NSError *err))completion;

Objective-C: Method's return value and Completion block, how are they executed?

I make an photography app in iPhone and I have these 3 classes: ViewController, CaptureManager, and ImgProcessor.
ViewController:
-(IBAction)takePic:(id)sender{
images = [captureManager takeMultipleImagesWithCompletion:^{
//Some UI related code..
[imgProcessor process:images];
}];
}
CaptureManager:
-(NSArray *)takeMultipleImagesWithCompletion:^(void)completionHandler{
// take picture codes...
completionHandler();
return arrayOfImagesTaken;
}
So far it works as desired: imgProcessor processes the images taken by captureManager. But I don't quite get the idea how this works. Bcos I called completionHandler before I return the array of images taken. How did this code executed? Is there a better solution to this?
Thanks!
You don't need to return the value images. You can pass it as an argument for the cmpletionHandler block.
-(void)takeMultipleImagesWithCompletion:(void (^)(NSArray *images))completionHnadler{
// take picture codes...
completionHnadler(arrayOfImagesTaken);
}
You can call it like this :
-(IBAction)takePic:(id)sender{
[captureManager takeMultipleImagesWithCompletion:^(NSArray *images){
[imgProcessor process:images];
}];
}
How it works ?
Here the block is used as a callback, it defines the code to be executed when a task completes. When the takeMultipleImagesWithCompletion is finished running, the block completionHnadler will be called.
Since your takeMultipleImagesWithCompletion executes the completion block synchronously, it doesn't need to take a completion block. It can just return the arrayOfImagesTaken and the caller can do whatever it wants with it.

Best Practice for calling a method programmatically where the methodName is -(void)animatePageX where x =1 thru 25

I am doing a children's book using Leaves. I want to have a different animated image and sound play for each page. I have figured out how to do the animation, I have it in a method that i can pass all the animation objects for each page. But each page is so different that I am ending up writing a different method for each page. I have a pageNum var that I want to call each pages method page 5 animation method would be -(void)animatePage5, and so on.
But I can not figure out how to build the method call so that it has the pageNum object in it.
I know this is easy, but I just can not find an answer on google, or stack overflow.
I might be too close to the forest to see the trees.
What is the simple, best practice for this type of method call.
Thanks for helping out a noob....
I don't know about an 'easy' solution, I've certainly never needed this before.
I think this is a step to what you're looking for, but I'd consider refactoring your code so the method takes a parameter like suggested in the other answers: -(void)animatePage:(int) page
NSString *selectorName = [NSString stringWithFormat:#"animatePage%d", pageNumber];
SEL s = NSSelectorFromString(selectorName);
if ([self respondsToSelector:s]) [self performSelector:s];
A simple answer would be to have a method called -(void)animatePage:(int)page where you either have a massive switch statement containing your code from each method, or just a call to each method.
However, I eagerly await an objective-C superhero suggesting doing something clever with #selector or method swizzling or some other scary technique.
You could use a switch statement to redirect the method call to the right method:
-(void)animagePage:(int)pagenum
{
switch (pagenum) {
case 1: [self animatePage1]; break;
case 2: [self animatePage2]; break;
case 3: [self animatePage3]; break;
...
case 25: [self animatePage25]; break;
}
}
Or you can create a string and then convert it to a #selector:
NSString* methodName = [NSString stringWithFormat:#"animatePage%d", pagenum];
SEL aSelector = NSSelectorFromString( methodName );
[self performSelector:aSelector];

Resources