Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Xcode IDE Plugin error: "Could not find class named..."

I've developed my own custom Xcode .ideplugin to add a custom object to Xcode's Object Library pane. I have my custom object template based on a class I called IBMyCustomObject, which in turn has a runtimeClassName of a class I called MyCustomObject (a runtime class name is the name of the class that will be instantiated at runtime when the Xib file is loaded).

After tons of research, I've been able to successfully get this working. I can now drag and drop my custom object from the Objects Library pane to Xib files normally, set the object properties in the inspector pane, and everything else is working great. The only problem comes at compile time, where Xcode's ibtool gives me the following error when the Xib file is compiled:

Exception name: NSInvalidArgumentException
Exception reason: Could not find class named MyCustomObject

And here is the full exception backtrace log:

Exception backtrace: 
  0. CoreFoundation           0x0226d6d8 __exceptionPreprocess
  1. libobjc.A.dylib          0x01fe98b6 objc_exception_throw
  2. CoreFoundation           0x022fd721 -[NSException raise]
  3. ???                      0x000116b8 [IBCocoaTouchToolObjectPackage initWithRequest:]
  4. ???                      0x00010597 [IBCocoaTouchTool .cxx_destruct]
  5. ???                      0x0000b63d [IBCocoaTouchTool compileNibForRequest:minimumCompatibility:layoutInfo:]
  6. IBFoundation             0x00362c51 __72-[IBMessageReceiveChannel deliverMessage:toTarget:withArguments:result:]_block_invoke
  7. IBFoundation             0x00362996 -[IBMessageReceiveChannel deliverMessage:toTarget:withArguments:result:]
  8. IBFoundation             0x00362673 __80-[IBMessageReceiveChannel runBlockingReceiveLoopNotifyingQueue:notifyingTarget:]_block_invoke
  9. libdispatch.dylib        0x029c2444 _dispatch_barrier_sync_f_slow_invoke
 10. libdispatch.dylib        0x029d34b0 _dispatch_client_callout
 11. libdispatch.dylib        0x029c1766 _dispatch_main_queue_callback_4CF
 12. CoreFoundation           0x022d2b6e __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
 13. CoreFoundation           0x022137eb __CFRunLoopRun
 14. CoreFoundation           0x02212bf3 CFRunLoopRunSpecific
 15. CoreFoundation           0x02212a0b CFRunLoopRunInMode
 16. Foundation               0x01c1fe55 -[NSRunLoop(NSRunLoop) runMode:beforeDate:]
 17. ???                      0x0003ac67 [IBAbstractCocoaTouchTool startServingReceiveChannel:]
 18. ???                      0x0003ad62 [IBAbstractCocoaTouchTool startServingSocket:]
 19. ???                      0x0003aec7 [IBAbstractCocoaTouchTool protocolCapabilities]
 20. ???                      0x0001053e [IBCocoaTouchTool .cxx_destruct]
 21. libdyld.dylib            0x9313d725 start
Exception info:{
}

Any ideas on how can I have Xcode (more specifically ibtool) know about the MyCustomObject class so that it could find it at compile time? I've tried many things, including placing MyCustomObject in a framework and loading the bundle at runtime, but nothing worked at all. If I replace IBMyCustomObject's runtimeClassName with NSMutableDictionary (or any other Foundation or UIKit class) instead of MyCustomObject, everything works perfectly, but I really need to use my own MyCustomObject class instead.

P.S.: For everyone interested in developing similar plugins, I'll be posing all my findings in a detailed blog post on sensiblecocoa.com (the framework using the plugin) once I have everything figured out.

like image 332
Tarek Avatar asked Aug 23 '13 12:08

Tarek


1 Answers

Ok, it turns out that Xcode (more specifically ibtool) is spawning an entirely new process called "Interface Builder Cocoa Touch Tool" during compile time, which explains why loading the MyCustomClass bundle had no effect. One possible solution to this that I considered was using dylib injection to inject the MyCustomClass library into the newly spawned process, but none of the techniques I found were reliable enough for robust and stable production code.

I finally ended up using NSMutableDictionary instead of MyCustomClass, which compiled perfectly. I then used a setter property method in the object owner class to convert the loaded NSMutableDictionary into MyCustomClass, then manually assigned all the dictionary keys to their respective properties. As I said before, I'll be posting all the plugin development details on the sensiblecocoa.com blog page.

like image 189
Tarek Avatar answered Oct 22 '22 13:10

Tarek