Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does -[NSObject autoContentAccessingProxy] work at all?

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?

like image 278
GBegen Avatar asked Nov 04 '11 21:11

GBegen


Video Answer


1 Answers

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.

like image 168
0xced Avatar answered Sep 22 '22 09:09

0xced