GBe*_*gen 7 cocoa-touch objective-c ios
我正在尝试使用http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html#//apple_ref/occ/instm/中-[NSObject autoContentAccessingProxy]
所述的内容.NSObject/autoContentAccessingProxy.
我试图代理的对象实现NSDiscardableContent
协议并-autoContentAccessingProxy
成功返回非零值.
但是,如果我尝试向代理发送消息,我总是得到一个NSInvalidArgumentException
"*** - [NSProxy methodSignatureForSelector:]调用!"的原因.
我理解如果我正在编写自己NSProxy
的类,我将不得不实现该-methodSignatureForSelector:
方法,但在这种情况下,我不是在编写代理,只是尝试使用文档化方法提供的代理.对于它的价值,我可以看到代理实际上是类型NSAutoContentAccessingProxy
,所以我希望该类确实有一个实现-methodSignatureForSelector:
.
这是使用NSPurgeableData实例而不是我的自定义类的一小段代码.这个小块有完全相同的问题.
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];
Run Code Online (Sandbox Code Playgroud)
我在-autoContentAccessingProxy
这里对这种方法有一些误解,还是只是完全被打破了?
0xc*_*ced 11
您可以通过重新实现NSAutoContentAccessingProxy
类的功能但没有错误来修复此错误.我写了这样一堂课:XCDAutoContentAccessingProxy
.autoContentAccessingProxy
在main
调用函数之前替换该方法; 这种情况发生在+load
方法中.因此,您所要做的就是在应用程序中编译以下代码,autoContentAccessingProxy
并按预期运行.
请注意,与我之前的答案不同,您实际上可以在运送应用程序中使用此解决方案.
#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
Run Code Online (Sandbox Code Playgroud)
更新此错误已在OS X 10.8上修复.根据OS X Mountain Lion发行说明:
在Mac OS 10.8之前, - [NSObject autoContentAccessingProxy]返回了一个没有正确实现消息转发的对象.此代理现在在Mac OS 10.8上正常运行.
因此,只有在针对OS X 10.7或更早版本时才需要编译上述代码.
你说得完全正确,-autoContentAccessingProxy
完全崩溃了。NSAutoContentAccessingProxy
是 的子类NSProxy
,因此应该实现methodSignatureForSelector:
和forwardInvocation:
方法,或者forwardingTargetForSelector:
如果在 iOS 4 或更高版本上运行,则应该实现 和 方法。
这是通过在运行时NSAutoContentAccessingProxy
添加methodSignatureForSelector:
和方法来修复类的核心方法。forwardInvocation:
只需将以下内容添加到您的项目中(不要使用 ARC 进行编译)。
#import <mach-o/dyld.h>
#import <mach-o/nlist.h>
__attribute__((constructor)) void FixAutoContentAccessingProxy(void);
static id _target(id autoContentAccessingProxy);
static NSMethodSignature *NSAutoContentAccessingProxy_methodSignatureForSelector(id self, SEL _cmd, SEL selector);
static void NSAutoContentAccessingProxy_forwardInvocation(id self, SEL _cmd, NSInvocation *invocation);
__attribute__((constructor)) void FixAutoContentAccessingProxy(void)
{
Class NSAutoContentAccessingProxy = objc_lookUpClass("NSAutoContentAccessingProxy");
Method methodSignatureForSelector = class_getInstanceMethod([NSObject class], @selector(methodSignatureForSelector:));
Method forwardInvocation = class_getInstanceMethod([NSObject class], @selector(forwardInvocation:));
class_addMethod(NSAutoContentAccessingProxy, @selector(methodSignatureForSelector:), (IMP)NSAutoContentAccessingProxy_methodSignatureForSelector, method_getTypeEncoding(methodSignatureForSelector));
class_addMethod(NSAutoContentAccessingProxy, @selector(forwardInvocation:), (IMP)NSAutoContentAccessingProxy_forwardInvocation, method_getTypeEncoding(forwardInvocation));
}
static id _target(id autoContentAccessingProxy)
{
static uint32_t targetIvarOffset;
static dispatch_once_t once;
dispatch_once(&once, ^{
struct nlist symlist[] = {{"_OBJC_IVAR_$_NSAutoContentAccessingProxy._target", 0, 0, 0, 0}, NULL};
for(uint32_t i = 0; i < _dyld_image_count(); i++)
{
if (nlist(_dyld_get_image_name(i), symlist) == 0 && symlist[0].n_value != 0)
{
uint32_t *_OBJC_IVAR_NSAutoContentAccessingProxy_target = (uint32_t*)((uint32_t)_dyld_get_image_header(i) + symlist[0].n_value);
targetIvarOffset = *_OBJC_IVAR_NSAutoContentAccessingProxy_target;
break;
}
}
});
return *(id*)((uint32_t)autoContentAccessingProxy + targetIvarOffset);
}
static NSMethodSignature *NSAutoContentAccessingProxy_methodSignatureForSelector(id self, SEL _cmd, SEL selector)
{
return [_target(self) methodSignatureForSelector:selector];
}
static void NSAutoContentAccessingProxy_forwardInvocation(id self, SEL _cmd, NSInvocation *invocation)
{
[invocation setTarget:_target(self)];
[invocation invoke];
}
Run Code Online (Sandbox Code Playgroud)
此解决方法应仅用于演示如何NSAutoContentAccessingProxy
损坏。无论如何,这仅适用于模拟器,因为nlist
调用将在设备上失败。APEFindSymbol
实际上,您可以通过使用APELite-arm来使其在设备上工作,但nlist
我不推荐它。
您绝对应该向 Apple提交有关它的错误报告。