Using method_exchangeImplementations with block_invoke methods - objective-c

I'm trying to replace method implementation with the following code
BOOL ct_hookMethod(Class originalClass, SEL originalSelector, Class swizzledClass, SEL swizzledSelector)
{
Method originalMethod = class_getInstanceMethod(originalClass, originalSelector);
Method swizzledMethod = class_getInstanceMethod(swizzledClass, swizzledSelector);
if (originalMethod && swizzledMethod)
{
method_exchangeImplementations(originalMethod, swizzledMethod);
return YES;
}
return NO;
}
It works for selectors like -[xxxView runRequest:], but not for methods like -[xxView runRequest:]_block_invoke:.
Does anyone know how to hook them?

Related

OCMVerify crashes test after a mocked callback

I have a method from a class under tests which takes two delegates: the second delegate will call a method after the first delegate will be called with a callback function as input.
#implemenation ClassUnderTest
...
- (void) methodWithMultipleCallbacks: (id<MyDelegate>) delegate
withSecondDelegate: (id<MyDelegateWithCallback>) delegateWithCallback {
for (int i = 0; i < 2; i++){
Callback callback = ^(int input) {
NSLog(#"%d-th callback", i);
NSLog(#"input = %d", input);
};
[delegateWithCallback fetchInt:callback];
}
[delegate delegateDoStuff:32];
}
But the strange thing happens: I tried to test it using OCMock, mocking both delegates, but the crashes, and I got a EXEC_BAD_ACCESS.
I am utterly confused and would really appreciate any help here! Here's the test function
- (void) testWithMultipleCallbacks {
id <MyDelegateWithCallback> mockDelegateWithCallback = OCMProtocolMock(#protocol(MyDelegateWithCallback));
OCMStub([mockDelegateWithCallback fetchInt:[OCMArg any]]).andDo(^(NSInvocation *invocation) {
void (^block)(int) = NULL;
[invocation getArgument:&block atIndex:2];
NSLog(#"got here");
block(33);
});
[_classUnderTest methodWithMultipleCallbacks: _mockedDelegate withSecondDelegate: mockDelegateWithCallback];
OCMVerify(OCMTimes(1), [_mockedDelegate delegateDoStuff:[OCMArg any]]);
}

How to call - (void) function in ordinary void function in cocoa

for example:
-(void) myExample {
..do something
}
void myOther(){
how to call myExample function here
}
When you call myOther, pass self reference. you should define the C method like this:
void myOther(id callBack)
Now you have self reference in c function.
void myOther(id callBack){
[callBack myExample];
}
If both methods are in same Class than you can directly call First method from Second methods as follows:
-(void) myExample {
..do something
}
void myOther(){
call to myExample function
[self myExample];
}
read docs here: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithObjects/WorkingwithObjects.html
void getInputSource() {
TISInputSourceRef source = TISCopyCurrentKeyboardLayoutInputSource();
NSLog(#"languages: %#", TISGetInputSourceProperty(source, kTISPropertyBundleID));
NSLog(#"localized name: %#", TISGetInputSourceProperty(source, kTISPropertyLocalizedName));
[self awakeFromNib];
}
-(void) awakeFromNib {
self.statusBar = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
NSImage* icon = [NSImage imageNamed:#"icon.png"];
self.statusBar.image = icon;
}

Objective-C passing parameters in void method

How would I go about passing parameters when calling a void method? I understand that you can do something like this:
-(void)viewDidLoad {
[self callMethod];
}
-(void)callMethod {
//stuff here
}
But how would I pass a parameter, such as an NSString, to the callMethod method?
Here is an example with an integer parameter.
-(void)viewDidLoad {
[self callMethodWithCount:10];
}
-(void)callMethodWithCount:(NSInteger)count {
//stuff here
}
In objective-c the parameters are included within the method name. You can add multiple parameters like this:
-(void)viewDidLoad {
[self callMethodWithCount:10 animated:YES];
}
-(void)callMethodWithCount:(NSInteger)count animated:(BOOL)animate{
//stuff here
}
It seems you may be misunderstanding what the void in the beginning of the method means. It's the return value. For a void method, nothing is returned from calling the method. If you wanted to return a value from your method you would do it like this:
-(void)viewDidLoad {
int myInt = [self callMethodWithCount:10 animated:YES];
}
-(int)callMethodWithCount:(NSInteger)count animated:(BOOL)animate{
return 10;
}
You define your method to return an int (in this example it always returns 10.) Then you can set an integer to the value returned by calling the method.
- (void)callMethod:(NSString *)string
{
}
Where string is your parameter so you would call
NSString *myString = #"your string here......";
[self callMethod:myString];

How can I know whether an instance implements a method in Objective-C?

I would like to know if an instance implements a specific method. I could use respondsToSelector: but it returns YES if the instance inherits the method...
I could loop through the methods of class_copyMethodList(), but since I might want to check a lot of instances, I wanted to know if there was a simpler solution (like repondsToSelector:, but restricted to the class itself...)
edit: since I really think there is no function or method doing that, I wrote mine. Thanks for your answers, here is the method if it can be of any use :
+ (BOOL)class:(Class)aClass implementsSelector:(SEL)aSelector
{
Method *methods;
unsigned int count;
unsigned int i;
methods = class_copyMethodList(aClass, &count);
BOOL implementsSelector = NO;
for (i = 0; i < count; i++) {
if (sel_isEqual(method_getName(methods[i]), aSelector)) {
implementsSelector = YES;
break;
}
}
free(methods);
return implementsSelector;
}
It's probably easier to check whether the method your own class returns is the same or different than the method your superclass returns.
if ([[obj class] instanceMethodForSelector:sel] != [[obj superclass] instanceMethodForSelector:sel]) {
NSLog(#"%# directly implements %#", [obj class], NSStringFromSelector(sel));
}
instance responds and super does not:
-(BOOL) declaresSelector:(SEL)inSelector {
return [self respondsToSelector:inSelector] && ![super respondsToSelector:inSelector];
}
instance responds and is different than super:
-(BOOL) implementsSelector:(SEL)inSelector {
return [self respondsToSelector:inSelector] && !( [super respondsToSelector:inSelector] && [self methodForSelector:inSelector] == [super methodForSelector:inSelector] );
}
According to Apple documents you should call respondsToSelector before methodForSelector.
You can use reflection to do that.

OCMock: Make a stub do something

I'm getting used to OCMock. Coming from a Java/JMock background I'm now looking for the ability to say [[[myMock stub] returnValueFromCustomMethod] someMockedMethod]; where returnValueFromCustomMethod is defined in the test class. I was originally thinking something along the terms of [[[myMock stub] usingSelector:#selector(myMethod:)] someMockedMethod]; but after writing I wonder if my first approach makes more sense. Either way, could someone show me if and how this can be done?
My original answer was off-track: OCMock doesn't support this! If you wanted to change OCMock to support this, you would need to do something like adding a BOOL returnValueIsFromInvocation field to OCMockRecorder, and add a method to set this up:
- (id)andReturnResultOfInvocation:(NSInvocation *)anInvocation {
returnValueIsFromInvocation = YES;
returnValueIsBoxed = NO;
returnValueShouldBeThrown = NO;
[returnValue autorelease];
returnValue = [anInvocation retain];
return self;
}
Then teach setUpReturnValue to call the invocation (changes are in bold):
- (void)setUpReturnValue:(NSInvocation *)anInvocation
{
if (returnValueIsFromInvocation) {
NSInvocation *returnValueInvocation = (NSInvocation *)returnValue;
[returnValueInvocation invoke];
void *buffer = malloc([[anInvocation methodSignature] methodReturnLength]);
[returnValueInvocation getValue:buffer];
[anInvocation setReturnValue:buffer];
free(buffer);
}
else if(returnValueShouldBeThrown)
{
#throw returnValue;
}
else if(returnValueIsBoxed)
{
if(strcmp([[anInvocation methodSignature] methodReturnType],
[(NSValue *)returnValue objCType]) != 0)
[NSException raise:NSInvalidArgumentException
format:#"Return value does not match method signature."];
void *buffer = malloc([[anInvocation methodSignature] methodReturnLength]);
[returnValue getValue:buffer];
[anInvocation setReturnValue:buffer];
free(buffer);
}
else
{
const char *returnType = [[anInvocation methodSignature] methodReturnType];
const char *returnTypeWithoutQualifiers = returnType + (strlen(returnType) - 1);
if(strcmp(returnTypeWithoutQualifiers, #encode(id)) == 0)
[anInvocation setReturnValue:&returnValue];
}
}
This change is difficult to do by introducing subclasses because you have to override the methods that return OCMockRecorders (like stub, expect and so on) but the concrete subclasses of OCMockObject (OCClassMockObject and OCProtocolMockObject) are hidden by the framework.