1

Let's say I wanted to be able to intercept any method calls to a UIViewController subclass.

First of all, I swizzle the +(instancetype)alloc method and I check if the current instance isKindOfClass:[UIViewController class]. If it is I go ahead and instantiate my proxy with the target.

///swizzled Alloc
+ (instancetype)monitoredAlloc {
     id obj = [self monitoredAlloc];
     if([obj isKindOfClass:[UIViewController class]]) {
        id proxy = [PMGProxy proxyWithObject:obj];
        return proxy;
     }
    return [self monitoredAlloc];
}
 ---------------------------------------
/// Proxy class
@implementation PMGProxy

+ (instancetype)proxyWithObject:(id)obj {
    PMGProxy *proxy = [self alloc];
    proxy.obj = obj;
    return proxy;
}


- (void)forwardInvocation:(NSInvocation *)invocation
{
    [invocation setTarget:_obj];
    [invocation invoke];
}

-(NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
    return [self.obj methodSignatureForSelector:sel];
}

- (Class)class {
    return [self.obj class];
}

The problem is that I get crashes, so I would expect the implementation of my Proxy is wrong... What am I doing wrong?

Here is the exception:

*** Terminating app due to uncaught exception 'NSGenericException', reason: 'This coder requires that replaced objects be returned from initWithCoder:'
iOSAddicted
  • 389
  • 1
  • 17
  • Down this path lies madness. Sorta kinda maybe borderline useful for debugging sometimes, but not useful for anything else. And even in the context of debugging, you're going to run into a raft load of problems if you try to do this kind of shenanigans to system provided classes. – bbum Feb 03 '18 at 22:20
  • I am not asking here if this is borderline useful or not, not planning on pushing this code to the apple atore. It is more for learning purposes than anything else. – iOSAddicted Feb 03 '18 at 22:25
  • Down this path still lies madness. :). The error method is likely fallout of an implementation detail of the UIViewController class hierarchy (or fallout from secure coding, actually). The problem is that as much as duck typing works really well with classes, it quickly runs afoul of implementation details and implementation assumptions when you try to do wholesale replacement in complex, pre-exisitng, class hierarchies. – bbum Feb 04 '18 at 02:46
  • 1
    You'll [likely] find more value in subclassing and overriding all the methods you want/need to log. Or to use swizzling to concisely replace and log on specific methods. Tedious, more effort, but more precisely focused on the public API. – bbum Feb 04 '18 at 02:47

1 Answers1

0

From the error it seems that the coder is only happy to accept a different class returned from initCoder: rather than earlier in the process at the alloc stage.

Might be worth looking up NSSecureCoding for more detail on the whole process.

While you’re at it, take a look at the stack track that resulted in your exception, it will give you a bit more perspective on just how deep this rabbit hole goes.

jjrscott
  • 1,386
  • 12
  • 16