Search code examples
macoscocoascreensaver

Why would method swizzling be bypassed by the screen saver?


I'm developing a screensaver for Mac OS X and I need to do some method swizzling so I made a small experiment:

@implementation CAHTTPCookieStorage
+ (void) highjack {
    NSLog(@"Attempting to highjack cookies.");
    Class originalClass = [NSHTTPCookieStorage class];
    Method originalMeth = class_getClassMethod(originalClass, @selector(sharedHTTPCookieStorage));
    Method replacementMeth = class_getClassMethod([self class], @selector(patchedSharedHTTPCookieStorage));
    method_exchangeImplementations(originalMeth, replacementMeth);
}

+ (NSHTTPCookieStorage*) patchedSharedHTTPCookieStorage {
    NSLog(@"Cookies have been highjacked!!!!");
    return [CAHTTPCookieStorage patchedSharedHTTPCookieStorage];
}
@end

I'm calling CAHTTPCookieStorage.highjack() from my app from AppDelegate.init() and from my screensaver from the ScreenSaverViewSubclass.init(...). While running my app or the screensaver in preview mode (inside the system preferences), it works fine, but when I run it as a proper screensaver I can see the message "Attempting to highjack cookies." but never "Cookies have been highjacked!!!!".

Any ideas what might be going wrong? Maybe an issue with threads? is method swizzling per thread?


Solution

  • Further investigation on this proved that this was true only in 10.10 in dual monitor mode but not in 10.9 with two monitors or 10.10 with a single monitor. I'm not sure what caused it, but using the +load method for doing the swizzling solved it:

    + (void) load {
        NSLog(@"Attempting to highjack cookies.");
        Class originalClass = [NSHTTPCookieStorage class];
        Method originalMeth = class_getClassMethod(originalClass, @selector(sharedHTTPCookieStorage));
        Method replacementMeth = class_getClassMethod([self class], @selector(patchedSharedHTTPCookieStorage));
        method_exchangeImplementations(originalMeth, replacementMeth);
    }