PLPatchMaster: Swizzling in Style

17 Feb 2014, 14:56 PST

Introduction

Last year, I wrote a swizzling API for my own use in patching Xcode; I wanted an easy way to define new method patches, and the API wound up being pretty nice:

[UIWindow pl_patchInstanceSelector: @selector(sendEvent:) withReplacementBlock: ^(PLPatchIMP *patch, UIEvent *event) {
    NSObject *obj = PLPatchGetSelf(patch);
 
    // Ignore 'remote control' events
    if (event.type == UIEventTypeRemoteControl)
        return;
 
    // Forward everything else
    return PLPatchIMPFoward(patch, void (*)(id, SEL, UIEvent *), event);
}];

In light of Mattt Thompson's post on Method Swizzling today, I figured I'd brush it off, port it to armv7/armv7s/arm64, and share it publicly.

PLPatchMaster uses the same block trampoline allocator I originally wrote for PLBlockIMP, along with a set of custom trampolines.

It's similar to imp_implementationWithBlock() in implementation and efficiency; rather than simply re-ordering 'self' and '_cmd', we pass in enough state to allow forwarding the message to the original receiver's implementation.

Use it at your own risk; swizzling in production software is rarely, if ever, a particularly good idea.

Advanced Use

The library can also be used to register patches to be applied to classes that have not yet been loaded:

[[PLPatchMaster master] patchFutureClassWithName: @"ExFATCameraDeviceManager" withReplacementBlock: ^(PLPatchIMP *patch, id *arg) {
    /* Forward the message to the next IMP */
    PLPatchIMPFoward(patch, void (*)(id, SEL, id *));
        
    /* Log the event */
    NSLog(@"FAT camera device ejected");
}];

PLPatchMaster registers a listener for dyld image events, and will automatically swizzle the target class when its Mach-O image is loaded.

Source Code

The soure code is available via the official repository, or via the GitHub mirror.