Short explanation:
An object in NSDictionary seems to be over-released. Swizzling of an object's new function is involved and believed to be causing the problem.
Long explanation:
I am developing some unit-tests for code which has not been developed with unit-testing in mind. In order to replace objects created in the code with mock-objects, I am using swizzling.
I recently got the following set up:
- I have a singleton test-class which basically just contains a dictionary of test data.
- I have a test-case which creates a mock-object (MockA) which shall be sent to the tested function via swizzling, the function under test shall be run and the outcome examined.
- I have a cleanup phase
Now to some code:
Testcase (Note crash!!)
- (void)testLogin
{
[self swizzleLoginOperation];
MockLoginOperation* op = [MockLoginOperation new];
// *** op setup code here ***
[[TestSingleton sharedInstance].dataToShare setObject:op forKey:LOGIN_OPERATION];
// pseudo-code below
[classUnderTestInstance login];
// Assert something
// Cleanup
[self swizzleLoginOperation];
[[TestSingleton sharedInstance].dataToShare removeAllObjects]; // Crash!!
}
Swizzle functions
- (void)swizzleLoginOperation
{
Method origMethod = class_getClassMethod([LoginOperation class], @selector(new));
Method newMethod = class_getClassMethod([MockLoginOperation class], @selector(createLoginOperationTest));
c = object_getClass((id)[LoginOperation class]);
if(class_addMethod(c, origSel, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
{
class_replaceMethod(c, newSel, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
}
else
{
method_exchangeImplementations(origMethod, newMethod);
}
}
+ (LoginOperation*)createLoginOperationTest
{
NSDictionary* values = [TestSingleton sharedInstance].dataToShare;
LoginOperation* op = (LoginOperation*)[values objectForKey:LOGIN_OPERATION];
return op;
}
Function under test
- (void)login
{
LoginOperation* op = [LoginOperation new];
// More stuff which I have removed but still get the problem
}
Any ideas?
Update
To find the error I attempted to run this code:
for (NSString* key in self.dataToShare.allKeys)
{
NSObject* value = [self.dataToShare objectForKey:key]; // Crashes here
}
Crash Thread 1: EXC_BAD_ACCESS(code=1, address=…) In the log: *** -[MockLoginOperation retain]: message sent to deallocated instance 0x7fd7b31f5050