I have a pretty simple setup for this unit test. I have a class that has a delegate property:
@interface MyClass : NSObject
...
@property (nonatomic, weak) id<MyDelegateProtocol> connectionDelegate;
...
@end
and I set the delegate in my test:
- (void)testMyMethod_WithDelegate {
id delegate = mockDelegateHelper(); // uses OCMock to create a mock object
[[delegate expect] someMethod];
myClassIvar.connectionDelegate = delegate;
[myClass someOtherMethod];
STAssertNoThrow([delegate verify], @"should have called someMethod on delegate.");
}
But the delegate is not actually set on line 3 of my unit test, so #someMethod is never called. When I change it to
myClassIvar.connectionDelegate = delegate;
STAssertNotNil(myClassIvar.connectionDelegate, @"delegate should not be nil");
it fails there. I'm using ARC, so my hunch was that the weak property was being deallocated. Sure enough, changing it to strong
makes the STAssertNotNil
pass. But I don't want to do that with a delegate, and I don't understand why that makes a difference here. From what I've read, all local references in ARC are strong
, and STAssertNotNil(delegate)
passes. Why is my weak delegate property nil when the same object in a local variable is not?
I am no ARC expert but my guess is that
mockDelegateHelper()
is returning a weak object. As a resultdelegate
is nil before the second line of code executes. I would venture to guess that either themockDelegateHelper()
is the culprit or that OCMock is getting in the way with how it manipulates and creates objects.I don't really know what's happening here, but OCMock returns an autoreleased
NSProxy
-descendant from themockForProtocol:
method, which I think is right. Maybe ARC has problems with NSProxies? Anyway, I've overcome this problem by declaring the variable__weak
:It really doesn't need to be
__strong
(the default) in this case, as it's autoreleased and you're not keeping it around...This is a bug in the iOS runtime. The following discussion has more detail. In a nutshell, the iOS ARC runtime can't seem to handle weak references to proxies. The OSX runtime can.
http://www.mulle-kybernetik.com/forum/viewtopic.php?f=4&t=252
As far as I understand from the discussion a bug report has been filed with Apple. If anyone has a sensible idea for a workaround...
A workaround is to use Partial Mocks.