Mocking a method in OCMock for all instances of a class - objective-c

I want to mock an instance method for all instances of a class using OCMock however I don't have the instance of the class to override it rather it is created inside the method that I'm testing.
So my question is: is it possible to override this method for all instances of a class or will I need to inject that instance into the method rather than create it inside the method?
i.e.
[[ClassThatHasTheInstanceMethodToOverride andCall:#selector(callThisMethodInstead) onObject:self] someInstanceMethod];

I got there in the end with this set of methods:
Method originalMethod = nil;
Method swizzleMethod = nil;
#import <objc/runtime.h>
....
- (void) swizzleInstanceMethodForInstancesOfClass:(Class)targetClass selector:(SEL)selector
{
originalMethod = class_getInstanceMethod(targetClass, selector);
swizzleMethod = class_getInstanceMethod([self class], selector);
method_exchangeImplementations(originalMethod, swizzleMethod);
}
- (void) deswizzle
{
method_exchangeImplementations(swizzleMethod, originalMethod);
swizzleMethod = nil;
originalMethod = nil;
}

Related

Class method successfully called instance method

Everything I know about programming says that instance methods can call class methods, but class methods cannot call instance methods.
This post agrees...
Call instance method from class method
Yet miraculously the class method sharedInstance manages to call instance method init. What am I missing ??
static iRpDatabase *sharedDatabase;
#implementation iRpDatabase
{
}
+(iRpDatabase*)sharedInstance
{
if(sharedDatabase == nil)
{
sharedDatabase = [[self alloc] init];
}
return sharedDatabase;
}
// this is an instance method, called from class method above.
-(id)init
{
if (self = [super init]) {
someInstanceVariable = XYZ;
[self someInstanceMethod];
}
return self;
}
The statement that a class method can't call instance methods means that the class method can't call instance methods on self since self represents the class, not an instance of the class.
In the sharedInstance method you are calling an instance method but it is being called on a specific instance of the class. That's fine.
Think of this example:
+ (void)someClassMethodOfiRpDatabase {
NSString *str = #"Hello";
NSInteger len = [str length]; // look - I called an instance method
}
This example in no different than your sharedInstance method question. It's fine to call instance methods on a specific instance of an object, even if you happen to be in some class method.

Is method a class method or instance method

In my code I want to know if a method is a class method or an instance method. The code I am currently using works, but I wonder if there is a beter way.
Current code to "detect" if it is a class method or instance:
Method method = class_getInstanceMethod(class, selector);
if (method) {
__strong Class object = [[class alloc] init];
objc_msgSend(object, selector);
}else {
method = class_getClassMethod(class, selector);
if (method) {
objc_msgSend(class, selector);
}
}
There's very little that you can improve beyond two if statements. You can use respondsToSelector: method instead, but since you do not have an object to start with, you will end up with an if inside an if rather than an a better-looking else if:
if ([class respondsToSelector:selector]) {
// Call class method
} else {
id object = [[class alloc] init];
if ([object respondsToSelector:selector]) {
// Call instance method
}
}
If you could modify your program flow to start with an object instead of a class, you coud do this instead:
if ([object respondsToSelector:selector]) {
// Call instance method
} else if ([[object class] respondsToSelector:selector]) {
// Call class method
}

My isa-swizzling breaks KVO

I'm trying to implement isa swizzling because I need some actions to happen in dealloc method of certain object. I'm overriding - (Class)class; method to return original class (as KVO does). Everything works fine, until I try to add observer to swizzled object. It just crashes.
0x00000000 in 0x00000000 ()
0x0091d22a in
_NSKeyValueRetainedObservationInfoForObject ()
0x0092ec88 in -[NSObject(NSKeyValueObserverRegistration) _addObserver:forProperty:options:context:] ()
0x0092d6fd in -[NSObject(NSKeyValueObserverRegistration) addObserver:forKeyPath:options:context:] ()
Here is implementation of swizzling
- (void)swizzleClass
{
NSString *proxyClassName = [NSString stringWithFormat:#"MDSwizzled_%#", NSStringFromClass(self->isa)];
Class proxyClass = NSClassFromString(proxyClassName);
if (!proxyClass)
proxyClass = [self createProxyClassWithName:proxyClassName];
object_setClass(self, proxyClass);
}
- (Class)createProxyClassWithName:(NSString *)proxyClassName
{
const char *c_proxyClassName = [proxyClassName cStringUsingEncoding:NSUTF8StringEncoding];
Class proxyClass = objc_allocateClassPair(self->isa, c_proxyClassName, 0);
Class dummyClass = [MDDummy class];
class_addMethodFromClass(proxyClass, dummyClass, #selector(dealloc));
class_addMethodFromClass(proxyClass, dummyClass, #selector(class));
objc_registerClassPair(proxyClass);
return proxyClass;
}
MDDummy it's just a class holding method in convinietn way (there is no difference between this and adding raw functions).
#implementation MDDummy
- (void)dealloc
{
//Special thinngs
[super dealloc];
}
- (Class)class
{
return //original class;
}
#end
EDIT:
Here's implementation of class_addMethodFromClass function:
void class_addMethodFromClass(Class class, Class sourceClass, SEL selector)
{
Method method = class_getInstanceMethod(sourceClass, selector);
IMP methodImplementation = method_getImplementation(method);
const char *types = method_getTypeEncoding(method);
class_addMethod(class, selector, methodImplementation, types);
}
You should check out how Mike Ash handles this: https://github.com/mikeash/MAZeroingWeakRef
Summary: handle swizzling a KVO-swizzled subclass differently--you'll have to patch the KVO methods in the KVO subclass...

Objective C - Category to modify a singleton object?

I know that the whole point of singleton is to instantiate 1 instance of the onject and reuse it, but when it comes to unit testing I want to be able to renew the singleton object before every test.
I tried to use a category to access the singleton object and release it but It's not accessible by categories any idea what's the best way to achieve this?
#implementation SingletonClass
static SingletonClass *singleton;
+ (SingletonClass*)sharedInstance
{
if (!singleton)
{
singleton = [[SingletonClass alloc] init];
}
return singleton;
}
#end
.
#implementation SingletonClass(Unit Testing Additions)
+ (void)killInstance
{
// I get an error here and I cannot access the singleton Object
[singleton release], singleton = nil;
}
#end
By the very definition of singleton, you can't do this.
If it is your class, don't make it a singleton.
If it isn't your class, doing this will fail.
I'm not sure whether this will work, but maybe you could just override the sharedInstance class method and manage the singleton yourself:
#implementation SingletonClass (Unit Testing Additions)
static SingletonClass *myVeryOwnSharedInstance;
+ (SingletonClass *) sharedInstance
{
if (!myVeryOwnSharedInstance)
myVeryOwnSharedInstance = [[self alloc] init];
return myVeryOwnSharedInstance;
}
+ (void) killInstance
{
[myVeryOwnSharedInstance release];
// if release is overridden to do no-op, maybe just invoke -dealloc directly
myVeryOwnSharedInstance = nil;
}
#end
If you want access to your singleton global variable outside of the file in which it's declared, you'll need to make it globally accessible using extern.
At the top of SingletonClass.h, put this:
extern SingletonClass *singletonClassSingleton;
In your SingletonClass.m, use this:
SingletonClass *singletonClassSingleton = nil;
Then assuming you have #import "SingletonClass.h" in your unit test .m file, you should be able to add:
#implementation SingletonClass(Unit Testing Additions)
+ (void)killInstance
{
[singletonClassSingleton release], singletonClassSingleton = nil;
}
#end
The reason I've renamed singleton to singletonClassSingleton is that the variable is now global - if you have a bunch of singleton classes, you need these variables to have unique names, like dataManagerSingleton, resourceManagerSingleton or whatever.
Here is my own solution.
#implementation SingletonClass(Unit Testing Additions)
//Override
static SingletonClass *singleton;
+ (void)killInstance
{
// I get an error here and I cannot access the singleton Object
[singleton release], singleton = nil;
}
//Override
+ (SingletonClass*)sharedInstance
{
if (!singleton)
{
singleton = [[SingletonClass alloc] init];
}
return singleton;
}
#end

Objective-C Proper way to create class with only one instance

I am trying to implement a class, that subclasses NSObject directly, that can only have one instance available throughout the entire time the application using it is running.
Currently I have this approach:
// MyClass.h
#interface MyClass : NSObject
+(MyClass *) instance;
#end
And the implementation:
// MyClass.m
// static instance of MyClass
static MyClass *s_instance;
#implementation MyClass
-(id) init
{
[self dealloc];
[NSException raise:#"No instances allowed of type MyClass" format:#"Cannot create instance of MyClass. Use the static instance method instead."];
return nil;
}
-(id) initInstance
{
return [super init];
}
+(MyClass *) instance {
if (s_instance == nil)
{
s_instance = [[DefaultLiteralComparator alloc] initInstance];
}
return s_instance;
}
#end
Is this the proper way to accomplish such a task?
Thanks
You need to do a little more than that. This describes how an objective-c singleton should be implemented: Objective-C Singleton
In your scenario, there is still a way to create a second instance of your class:
MyClass *secondInstance = [[MyClass alloc] initInstance]; //we have another instance!
What you want is to override your class's +(id)alloc method:
+(id)alloc{
#synchronized(self){
NSAssert(s_instance == nil, #"Attempted to allocate a second instance of singleton(MyClass)");
s_instance = [super alloc];
return s_instance;
}
return nil;
}