OCMock mock protocol's static class method. - objective-c

New in OCMock 3 is the ability to mock out class methods.
Is it possible to mock class methods defined in a protocol? i.e
#protocol AViewControllerProtocol <NSObject>
+ (Type)typeForViewController;
#end
Inside my unit test class
- (void)testProtocolClassMethod {
id mockedViewController = OCMProtocolMock(#protocol(AViewControllerProtocol));
//This line compiles fine, but throws an exception at run time.
OCMStub([mockedViewController typeForViewController]).andReturn(SomeType);
}
Exception throw
NSInvalidArgumentException: cannot stub/expect/verify method 'typeForViewController' because no such method exists in the mocked class

This looks like it was an oversight in OCMock 3.1, but you can make the fix yourself, if you want.
// OCProtocolMockObject.m
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
struct objc_method_description methodDescription = protocol_getMethodDescription(mockedProtocol, aSelector, YES, YES);
if(methodDescription.name == NULL)
{
methodDescription = protocol_getMethodDescription(mockedProtocol, aSelector, NO, YES);
}
// Add this case for required class methods
if (methodDescription.name == NULL)
{
methodDescription = protocol_getMethodDescription(mockedProtocol, aSelector, YES, NO);
}
// Add this case for optional class methods
if (methodDescription.name == NULL)
{
methodDescription = protocol_getMethodDescription(mockedProtocol, aSelector, NO, NO);
}
if(methodDescription.name == NULL)
{
return nil;
}
return [NSMethodSignature signatureWithObjCTypes:methodDescription.types];
}
I verified this fix with this test:
- (void)testProtocolClassMethod {
id mockedViewController = OCMProtocolMock(#protocol(AViewControllerProtocol));
// FIXED: This line compiles fine, but throws an exception at run time.
OCMStub([mockedViewController typeForViewController]).andReturn(SomeType);
Type type = [mockedViewController typeForViewController];
XCTAssertEqual(type, SomeType, #"Not equal!");
OCMVerify([mockedViewController typeForViewController]);
}
I'll put a request in on the project page for this.

Related

How to know if Objective C pointer is of `Class` type?

I would like to know if a pointer in my program is pointing to a Class type.
Something like:
if ([anObject isKindOfClass:[Class class]]])
This an error because [Class class] does not exist.
The closet I can come to is this:
NSLog(#"Will run");
const char *nameOfClass = class_getName(#"DoesNotExist");
if (nameOfClass == NULL || (strlen(nameOfClass) == 0)
{
NSLog(#"Not a class");
} else {
NSLog(#"String: %s", nameOfClass);
}
NSLog(#"Did run");
Where an empty const char *nameOfClass would tell me that it isn't in fact a Class object. Any other ideas?
There's an Obj-C runtime function called object_isClass.
#import <objc/runtime.h>
if (object_isClass(anObject))
Another valid approach would be to use class_isMetaClass(object_getClass(anObject)), since the class of a class is a metaclass.

Call original class method when called from child

I have a class A. B inherits A. Both classes implement method1 and method2.
method1 in A calls method2. It look like...
- (void)method1{
// some code
[self method2];
// some code
}
- (void)method2{
// some work
}
method1 in B calls super class method 1, and B also overrides method2.
- (void)method1{
[super method1];
}
- (void)method2{
// some work
}
Now, when B's instance is created and called method1 A's method1 calls method2 in B. What I want to do is calling A's method2 from A's method1 even when it is called from child(B).
In other words, in A's method1, I want to "forcefully" call the method in the same owner(class).
Is there any easy way to do it? I think I can do it with calling objective-c runtime functions but I want to know if there is easier way.
I know that this is not the design we should make in usual case, but from a little complex reason I have to do it. So please don't propose me to change the design or ask me what is the original goal of the program.
As a simplest solution I can come up with, use BOOL flag to decide how method2 should behave:
#interface B ()
#property (nonatomic) BOOL shouldCallSuperMethod2;
#end
#implementation B
- (void)method1{
self.shouldCallSuperMethod2 = YES;
[super method1];
self.shouldCallSuperMethod2 = NO;
}
- (void)method2{
if (self.shouldCallSuperMethod2) {
[super method2];
}
else {
// some work
}
}
#end
Note that this solution is not thread safe.
UPD Another interesting way, using runtime magic:
#import ObjectiveC.runtime;
#implementation B
- (void)method2 {
NSUInteger returnAddress = (NSUInteger)__builtin_return_address(0);
NSUInteger callerIMPAddress = 0;
SEL interestingSelector = #selector(method1);
// Iterate over the class and all superclasses
Class currentClass = object_getClass(self);
while (currentClass)
{
// Iterate over all instance methods for this class
unsigned int methodCount;
Method *methodList = class_copyMethodList(currentClass, &methodCount);
unsigned int i;
for (i = 0; i < methodCount; i++)
{
// Ignore methods with different selectors
if (method_getName(methodList[i]) != interestingSelector)
{
continue;
}
// If this address is closer, use it instead
NSUInteger address = (NSUInteger)method_getImplementation(methodList[i]);
if (address < returnAddress && address > callerIMPAddress)
{
callerIMPAddress = address;
}
}
free(methodList);
currentClass = class_getSuperclass(currentClass);
}
if (callerIMPAddress == (NSUInteger)[self methodForSelector:interestingSelector]) {
// method2 is called from method1, call super instead
[super method2];
}
else {
// some work
}
}
#end
Other interesting ways to identify caller may be found in answers to this question

How can method in Swift with inout parameter be used in Objective-C?

I want
func foo(inout stop: Bool) -> Void {
// ...
}
use in my Objective-C part. But it is never generated in Module-Swift.h header. If I mark it with #objc, the
Method cannot be marked #objc because the type of the parameter cannot
be represented in Objective-C
error occurs.
You can't use an inout parameter when bridging with Objective-C, but you can do something similar if you use an UnsafeMutablePointer<T> (T would be Bool in your case). It would look something like this:
#objc func foo(stop: UnsafeMutablePointer<Bool>) -> Void {
if stop != nil {
// Use the .pointee property to get or set the actual value stop points to
stop.pointee = true
}
}
Example
TestClass.swift:
public class TestClass: NSObject {
#objc func foo(stop: UnsafeMutablePointer<Bool>) -> Void {
stop.pointee = true
}
}
Objective-C:
TestClass *test = [[TestClass alloc] init];
BOOL stop = false;
[test foo:&stop];
// stop is YES here
Similarly to what happening with generics, inout is not objc-compatible.
One possible workaround is to embed your parameter(s) in a class (which is a reference type, hence passed by pointer and not by value):
#objc class MyFuncParams {
var stop: Bool
init(stop: Bool) {
self.stop = stop
}
}
and define the function to accept an instance of that class:
func changeParam(params: MyFuncParams) {
params.stop = true
}
Not an elegant way to solve the problem, but what's important is that it should work (never tried myself though).

Lua - Get instance of caller when using arguments using a (objective-)c bridge

I am trying to create a simple bridge between lua and my 'native' code. Using the following code I am adding an LuaObject class so that it can used from the lua code.
-(instancetype) init
{
if((self = [super init]))
{
// temp for testing script
L = luaL_newstate();
luaL_openlibs(L);
[self registerClazz:[LuaObject class]];
[self pushFunction:getObjectWithName name:#"getObjectWithName"];
}
return self;
}
-(void) pushFunction:(lua_CFunction)function name:(NSString*)name
{
lua_pushcfunction(L, function);
lua_setglobal(L, [name cStringUsingEncoding:NSASCIIStringEncoding]);
}
int getObjectWithName(lua_State *luaState)
{
NSString *name = [NSString stringWithUTF8String:lua_tostring(luaState, 1)];
lua_pop(luaState, 1);
LuaObject *luaObject = [objectMap objectForKey:name]
void *luaUserdataPtr = lua_newuserdata(luaState, sizeof(LuaObject*));
void *luaObjectPtr = (__bridge_retained void *)luaObjectPtr;
memcpy(ptr, &luaObjectPtr, sizeof(LuaObject*));
luaL_getmetatable(luaState, "LuaObject");
lua_setmetatable(luaState, -2);
return 1;
}
-(void) registerClazz:(Class)clazz
{
luaL_Reg methods[] = {
{ "talk", &proxyLuaObjectCall },
{ "say", &proxyLuaObjectCall },
{ NULL, NULL }
};
luaL_newmetatable(L, "LuaObject");
luaL_newlib(L, methods);
lua_setfield(L, -2, "__index");
lua_setmetatable(L, -2);
}
int proxyLuaObjectCall(lua_State *luaState, void* caller)
{
luaL_checkudata(luaState, 0, "LuaObject");
}
Now when proxyLuaObjectCall is called from lua, I want to be able to retrieve the instance of the LuaObject on which the method is being called. Above code works perfectly when calling a method without any arguments. But when calling a method that has any arguments the code fails with the error
bad argument #0 to '' (LuaObject expected, got table).
For example when using the following code in lua:
This works perfectly:
myObject = getObjectWithName("nominator");
myObject.talk();
This fails miserably
myObject = getObjectWithName("nominator");
myObject.say("And the winner is");
// Result: bad argument #0 to 'say' (LuaObject expected, got table).
--
myObject = getObjectWithName("nominator");
myObject.say("And the winner is", "Joan");
// Result: bad argument #0 to 'say' (LuaObject expected, got string).
I have tried changing the index when calling a method that has arguments but nothing on the stack contains a reference to the LuaObject instance.
What am I doing wrong here? What should I do to retrieve the instance of the LuaObject on which the method is called?
Everything looks good to me, but you probably should be calling it using the method notation:
myObject = getObjectWithName("nominator");
myObject:say("And the winner is");
myObject:say("") is the same as myObject.say(myObject, ""), which is what your API seems to expect.
On the other hand, #siffiejoe may be right as according to this PiL example, it should probably be luaL_checkudata(luaState, 1, "LuaObject"). In fact, you may need both of these changes to make it work.

Calling Obj-C From MonoTouch Using Selectors

Well I'm completely stumped - I cannot cal from Mono into Obj-C code using Selectors either. So as a last ditch attempt I'm posting the code:
#implementation MonoWrapper
- (id)init {
self = [super init];
if (self) {
NSBundle *main = [NSBundle mainBundle];
NSString *path = [main bundlePath];
const char *c_path = [path UTF8String];
[main autorelease];
[path autorelease];
chdir (c_path);
setenv ("MONO_PATH", c_path, 1);
setenv ("MONO_XMLSERIALIZER_THS", "no", 1);
setenv ("DYLD_BIND_AT_LAUNCH", "1", 1);
setenv ("MONO_REFLECTION_SERIALIZER", "yes", 1);
_domain = mono_jit_init_version ("MonoTouch", "v2.0.50727");
MonoAssembly *assembly = mono_assembly_open("PhoneGap.dll", NULL);
MonoImage *image = mono_assembly_get_image(assembly);
MonoClass *class = mono_class_from_name(image, "PhoneGap", "PhoneGap");
MonoMethodDesc *methodDesc = mono_method_desc_new("PhoneGap.PhoneGap:getInt", TRUE);
_callbackMethod = mono_method_desc_search_in_class(methodDesc, class);
/* allocate memory for the object */
_instance = mono_object_new (_domain, class);
/* execute the default argument-less constructor */
mono_runtime_object_init (_instance);
}
// Done
return self;
}
- (void)DoSomething {
int jim = 0;
}
- (int)multiplyA:(int)a {
void *params[] = { self, #selector(DoSomething), &a };
MonoObject *result = mono_runtime_invoke(_callbackMethod, _instance, params, NULL);
int n = *(int*)mono_object_unbox (result);
return n;
}
#end
And in MonoTouch:
using System;
using MonoTouch.ObjCRuntime;
namespace PhoneGap
{
public class PhoneGap
{
public PhoneGap ()
{
}
public int getInt(IntPtr instance, IntPtr sel, int val) {
Messaging.void_objc_msgSend (instance, sel);
return val * 2;
}
}
}
Can anyone tell me how to get the Target instance handle in Mono and how to get the Selector?
Thanks
James
The target/instance IntPtr is a pointer to the native instance. You would get this when you alloc the class.
For class/static method, the target/instance IntPtr is the native class descriptor. You can get this by creating a MonoMac.ObjcRuntime.Class and using its Handle property to get the native class descriptor.
The selector IntPtr is a pointer to a selector. You can get this by creating a MonoMac.ObjcRuntime.Selector and using its Handle property to get the native selector.
When creating a wrapper class for an NSObject, you would need to subclass NSObject and use the MonoMac.Foundation.Register attribute to set its Objc-C name. Then, when you new up the wrapper, it would alloc and init the underlying native instance and you'd be able to get that from the NSObject's Handle property. This also means that you can "unwrap" pointers to NSObjects to get the 1:1 managed wrapper using MonoMac.ObjcRuntime.Runtime.GetNSObject (IntPtr ptr).
In general, you're probably better off using the btouch tools to generate the binding for you.