1

I'm method swizzling a third party applications creation of NSMenuItems with SIMBL, but 50/50 of the time the menu-items are created before my method swizzling is initialized.

What is a clean way to make sure my swizzling always comes first? I guess I could swizzle applicationDidFinishLaunching: and continue my swizzling there. But I'm afraid I'm going to run in to the same error there, where applicationDidFinishLaunching will be called before my actual swizzle is in place.

John

2 Answers2

3

You'd want the swizzle to happen as soon as the libraries are loaded. You can do that via +initialize, +load, or a constructor function.

@bbum's answer to this question has a bit more information, along with one of his blog posts on the caveats of using these special class methods.

(And I'm purposely not questioning the wisdom of what you're doing ;) )

Community
  • 1
  • 1
Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • Well a constructor didn't do me any good. The code in the constructor was run after +load. So a follow up question would be, how would I make my SIMBL plugin to inject itself upon _start_ of the application, not with a few seconds delay? – John Williams Jan 13 '11 at 09:56
  • Also, in what other ways could I reach the NSMenuItem's from the 3rd party app without method swizzling them? I can reach the apps applicationDockMenu with one of their classes: [[[[AppController sharedController] applicationDockMenu:nil] itemArray] objectAtIndex:0] But there is no shared controller in the class that creates the menu bar. – John Williams Jan 13 '11 at 10:23
2

You can use constructor functions like this:

__attribute__((constructor)) static void do_the_swizzles()
{
    // Do all your swizzling here.
}

From GCC documentation:

The constructor attribute causes the function to be called automatically before execution enters main().

Note: Although this is originally from GCC, it also works in LLVM.

jhabbott
  • 18,461
  • 9
  • 58
  • 95