I am trying to make use of -[NSObject autoContentAccessingProxy]
as described at http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html#//apple_ref/occ/instm/NSObject/autoContentAccessingProxy.
The object I am trying to proxy implements the NSDiscardableContent
protocol and -autoContentAccessingProxy
successfully returns a non-nil value.
If, however, I try to send a message to the proxy, I always get an NSInvalidArgumentException
with a reason of "*** -[NSProxy methodSignatureForSelector:] called!".
I understand that if I was writing my own NSProxy
-based class, I would have to implement the -methodSignatureForSelector:
method, but in this case, I am not writing the proxy, just trying to use the proxy provided by the documented method. For what it's worth, I can see that the proxy is actually of type NSAutoContentAccessingProxy
, so I would expect that that class would indeed have an implementation for -methodSignatureForSelector:
.
Here is a small block of code using an NSPurgeableData instance instead of my custom class. This small block has exactly the same issue.
NSPurgeableData * data = [NSPurgeableData dataWithBytes:"123" length:3];
NSLog(@"data.length = %u", data.length);
id proxyData = [data autoContentAccessingProxy];
NSLog(@"proxyData.length = %u", [proxyData length]); // throws NSInvalidArgumentException!
[data endContentAccess];
[data release];
Do I have some misunderstanding of the -autoContentAccessingProxy
method here, or is it just completely broken?
You can fix this bug by reimplementing what the NSAutoContentAccessingProxy
class does but without the bugs. I have written such a class: XCDAutoContentAccessingProxy
. The autoContentAccessingProxy
method is replaced before your main
function is called; this happens in the +load
method. So all you have to do is compile the following code in your application and autoContentAccessingProxy
will behave as expected.
Note that unlike my previous answer, you can actually use this solution in a shipping application.
#if !__has_feature(objc_arc)
#error This code must be compiled with Automatic Reference Counting (CLANG_ENABLE_OBJC_ARC / -fobjc-arc)
#endif
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface XCDAutoContentAccessingProxy : NSProxy
+ (XCDAutoContentAccessingProxy *) proxyWithTarget:(id)target;
@property (nonatomic, strong) id target;
@end
@implementation XCDAutoContentAccessingProxy
@synthesize target = _target;
static id autoContentAccessingProxy(id self, SEL _cmd)
{
return [XCDAutoContentAccessingProxy proxyWithTarget:self];
}
+ (void) load
{
method_setImplementation(class_getInstanceMethod([NSObject class], @selector(autoContentAccessingProxy)), (IMP)autoContentAccessingProxy);
}
+ (XCDAutoContentAccessingProxy *) proxyWithTarget:(id)target
{
if (![target conformsToProtocol:@protocol(NSDiscardableContent)])
return nil;
if (![target beginContentAccess])
return nil;
XCDAutoContentAccessingProxy *proxy = [self alloc];
proxy.target = target;
return proxy;
}
- (void) dealloc
{
[self.target endContentAccess];
}
- (void) finalize
{
[self.target endContentAccess];
[super finalize];
}
- (id) forwardingTargetForSelector:(SEL)selector
{
return self.target;
}
- (NSMethodSignature *) methodSignatureForSelector:(SEL)selector
{
return [self.target methodSignatureForSelector:selector];
}
- (void) forwardInvocation:(NSInvocation *)invocation
{
[invocation setTarget:self.target];
[invocation invoke];
}
@end
UPDATE This bug is fixed on OS X 10.8. According to OS X Mountain Lion Release Notes:
Prior to Mac OS 10.8, -[NSObject autoContentAccessingProxy] returned an object that did not properly implement message forwarding. This proxy now behaves correctly on Mac OS 10.8.
So you need to compile the above code only if you are targeting OS X 10.7 or earlier.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With