Nil weak reference to mock object with ARC

Discussion of the OCMock framework. If you have patches we would prefer you to send them to the mailing list, but attaching them to a topic is possible, too.

Nil weak reference to mock object with ARC

Postby adamstegman » 03 Jan 2012, 01:55

Given a delegate protocol and a class that uses a delegate:

Code: Select all
@interface SomeClass : NSObject
@property (nonatomic, weak) id<SomeDelegateProtocol> delegate;
@end


Assigning a mock to that delegate property will see the mock immediately nilled, even though it's held elsewhere with a strong reference.

Code: Select all
- (void)testSomeMethod {
  SomeClass *object = [[SomeClass alloc] init];
  id delegate = [OCMockObject mockForProtocol:@protocol(SomeDelegateProtocol)];
  object.delegate = delegate;
  STAssertNotNil(delegate, @"should have created delegate");
  STAssertNotNil(object.delegate, @"should have assigned delegate");
}


The second assertion fails. The first assertion is there to illustrate that the actual object is not deallocated, just the weak reference is lost. I don't understand why the reference is nilled, since the object is not deallocated.

Github repo demonstrating the issue: https://github.com/adamstegman/ARCMock
adamstegman
 

Re: Nil weak reference to mock object with ARC

Postby amariottini » 22 Jan 2012, 23:37

I have exactly the same problem.
It seems a bug in OCMock.

Please let me know if you find a workaround.
Andrea
amariottini
 
Posts: 9
Joined: 22 Jan 2012, 23:35

Re: Nil weak reference to mock object with ARC

Postby erik » 24 Jan 2012, 00:32

In order to reproduce the problem I wrote a little app. It's actually checked into Github as "ArcExample" in the "Examples" folder. The code is as follows:

Code: Select all
#import <Foundation/Foundation.h>
#import <OCMock/OCMock.h>

@protocol SomeDelegateProtocol
- (void)doStuff;
@end

@interface SomeClass : NSObject
@property (nonatomic, weak) id<SomeDelegateProtocol> delegate;
@end

@implementation SomeClass
@synthesize delegate;
@end


int main (int argc, const char * argv[])
{
    @autoreleasepool {
        SomeClass *someObject = [[SomeClass alloc] init];
        id delegate = [OCMockObject mockForProtocol:@protocol(SomeDelegateProtocol)];
        someObject.delegate = delegate;
        NSLog(@"delegate = %@", delegate);
        NSLog(@"someObject = %@", someObject.delegate);
    }
    return 0;
}


This looks like it's the same as yours. Interestingly, though, this works. On my system (OS X 10.7.2, Xcode 4.2.1) the output is as follows:

Code: Select all
GNU gdb 6.3.50-20050815 (Apple version gdb-1708) (Thu Nov  3 21:59:02 UTC 2011)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin".tty /dev/ttys001
[Switching to process 1234 thread 0x0]
2012-01-23 23:25:54.317 ArcExample[1234:60b] delegate = OCMockObject[SomeDelegateProtocol]
2012-01-23 23:25:54.319 ArcExample[1234:60b] someObject = OCMockObject[SomeDelegateProtocol]
Program ended with exit code: 0


Any ideas? Could you try the ArcExample on your machine? What's different?

erik
erik
 
Posts: 90
Joined: 10 Oct 2009, 15:22
Location: Hamburg, Germany

Re: Nil weak reference to mock object with ARC

Postby amariottini » 24 Jan 2012, 10:33

A difference is I'm developing for iPhone, so I use libOCMock.a.

Anyway I downloaded your project and changed the reference to OCMock.framework because I have in another location.
I added the path even to Framework Search Paths built setting.

The project compile but on run:

GNU gdb 6.3.50-20050815 (Apple version gdb-1708) (Thu Nov 3 21:59:02 UTC 2011)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin".tty /dev/ttys001
[Switching to process 1687 thread 0x0]
dyld: Library not loaded: @rpath/OCMock.framework/Versions/A/OCMock
Referenced from: /Users/andrea/Library/Developer/Xcode/DerivedData/ArcExample-bpvymjucxoqabefxpbxfdczzfmhu/Build/Products/Debug/ArcExample
Reason: image not found
sharedlibrary apply-load-rules all

I'm new to Xcode, what is going wrong?
Andrea
amariottini
 
Posts: 9
Joined: 22 Jan 2012, 23:35

Re: Nil weak reference to mock object with ARC

Postby erik » 24 Jan 2012, 15:12

Apple's framework loading system has become more and more arcane over the years. I don't claim to fully understand it myself.

In a nutshell, the version of the OCMock framework you're using is built to allow for flexible installs, but that requires the binary that depends on the framework to know where to load it from. Yes, loading at runtime, which is what fails in your case, is different from finding the framework at build time.

Chances are that you need to set the "Runtime Search Paths" to the location the framework will be in relation to the binary at runtime. This article has more detail:

http://www.dribin.org/dave/blog/archives/2009/11/15/rpath/

Hope this helps.
erik
erik
 
Posts: 90
Joined: 10 Oct 2009, 15:22
Location: Hamburg, Germany

Re: Nil weak reference to mock object with ARC

Postby amariottini » 24 Jan 2012, 18:01

ok I made the ArcExample run and it works as expected.

I tried the exactly same thing (same main.m) with an iPhone project and this is the log:

GNU gdb 6.3.50-20050815 (Apple version gdb-1708) (Thu Nov 3 21:59:02 UTC 2011)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin".Attaching to process 4891.
2012-01-24 16:57:32.960 AssistentePersonale[4891:fb03] delegate = OCMockObject[SomeDelegateProtocol]
2012-01-24 16:57:32.962 AssistentePersonale[4891:fb03] someObject = (null)
Program ended with exit code: 0

So the problem is related only to iPhone (and maybe iPad development).
As I wrote in my previous post I used libOCMock.a for iPhone testing and not the OCMock.framework because I found this in a tutorial referred by OCMock site.
Maybe is possible to use OCMock.framework even on iPhone?
Andrea
amariottini
 
Posts: 9
Joined: 22 Jan 2012, 23:35

Re: Nil weak reference to mock object with ARC

Postby erik » 25 Jan 2012, 09:30

The reason why people go through the pain of setting up and using static libraries is that user frameworks are not supported on iOS.

The code in the library is obviously the same but in the past there have been issues with the way the code is linked, categories weren't included without special flags for example. I didn't have a chance to look into iOS 5 in detail so there may be the odd new "feature" that's causing these issues.

All that said, this looks like it's a bug in the iOS runtime. Did you file a bug with Apple, too?

erik
erik
 
Posts: 90
Joined: 10 Oct 2009, 15:22
Location: Hamburg, Germany

Re: Nil weak reference to mock object with ARC

Postby amariottini » 25 Jan 2012, 10:25

No,I think I can't ask Apple why a third party library doesn't work with my App on iOS5.
You could ask Apple why your library doesn't work on iOS5.
Anyway if you think it could be helpful, I'll file a bug...

Do you think is possible to find a workaround or the problem is completely an Apple problem?
Maybe you could slightly modify the code to work even on iOS5?
Andrea
amariottini
 
Posts: 9
Joined: 22 Jan 2012, 23:35

Re: Nil weak reference to mock object with ARC

Postby erik » 25 Jan 2012, 14:03

To create a workaround we need to understand the problem. At the moment I have no idea why the reference is nulled on iOS. I'll see what I can find out with the debugger, but I'm not too hopeful that I can see anything without delving into assembler, and that's going to be a lot of work...

Could you see whether the same problem occurs when you try to assign an instance of another class that derives from NSProxy, rather than NSObject? (Just create a class that inherits from NSProxy and repeat the test, no OCMock involved.) My suspicion, and it's just a suspicion, is that there's an issue with how ARC deals with weak references to proxies.

erik
erik
 
Posts: 90
Joined: 10 Oct 2009, 15:22
Location: Hamburg, Germany

Re: Nil weak reference to mock object with ARC

Postby amariottini » 25 Jan 2012, 16:15

I tried this code:

Code: Select all
#import <Foundation/Foundation.h>

@interface SomeClass : NSObject
@property (nonatomic, weak) id delegate;
@end

@implementation SomeClass

@synthesize delegate;

@end


@interface TargetProxy : NSProxy

- (id)initWithObject:(NSObject *)realObject;

@end

@implementation TargetProxy
{
    NSObject *_realObject;
}
- (id)initWithObject:(NSObject *)realObject {
    _realObject = realObject;
    return self;
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    return [_realObject methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    [anInvocation setTarget:_realObject];
    [anInvocation invoke];
    return;
}

@end

int main (int argc, const char * argv[])
{
   
    @autoreleasepool {
       
        SomeClass *someObject = [[SomeClass alloc] init];
        id delegate = [[TargetProxy alloc] initWithObject:@"XXXX"];
        someObject.delegate = delegate;
        NSLog(@"delegate = %@", delegate);
        NSLog(@"someObject.delegate = %@", someObject.delegate);
       
    }
    return 0;
}


The output is:
Code: Select all
GNU gdb 6.3.50-20050815 (Apple version gdb-1708) (Thu Nov  3 21:59:02 UTC 2011)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin".Attaching to process 4722.
2012-01-25 15:13:29.411 AssistentePersonale[4722:fb03] delegate = <TargetProxy: 0x6b55820>
2012-01-25 15:13:29.413 AssistentePersonale[4722:fb03] someObject = (null)
Program ended with exit code: 0


So the problems is relative to NSProxy and ARC.

I think now I can submit a bug report to Apple.
Andrea
amariottini
 
Posts: 9
Joined: 22 Jan 2012, 23:35

Next

Return to OCMock