ib_outlet Doesn't Create Accessors
Lately, I’ve been having fun with RubyCocoa while reading Brian Marick‘s RubyCocoa. It’s an entertaining book, and I really like RubyCocoa itself. But I hit a little gotcha. Take the following code:
PathController.rb
1 require 'osx/cocoa' 2 3 class PathController < OSX::NSObject 4 ib_outlet :path, :events 5 ib_action :choosePath 6 7 def choosePath(sender) 8 panel = OSX::NSOpenPanel.openPanel 9 panel.canChooseFiles = false 10 panel.canChooseDirectories = true 11 panel.allowsMultipleSelection = false 12 13 result = panel.runModal 14 if result == OSX::NSFileHandlingPanelOKButton then 15 self.path.title = panel.filename 16 end 17 end 18 end
What could be wrong with this? Turns out #ib_oulet does not define accessors for the instance variables it defines. Look at the exception:
1 OSX::OCMessageSendException: Can't get Objective-C method signature for selector 'events' of receiver #<PathController:0x2297be class='PathController' id=0x534ec0> 2 /Library/Frameworks/RubyCocoa.framework/Resources/ruby/osx/objc/oc_wrapper.rb:50:in `ocm_send' 3 /Library/Frameworks/RubyCocoa.framework/Resources/ruby/osx/objc/oc_wrapper.rb:50:in `method_missing' 4 /Users/francois/Projects/fsevtest/build/Debug/fsevtest.app/Contents/Resources/PathController.rb:27:in `choosePath' 5 /Users/francois/Projects/fsevtest/build/Debug/fsevtest.app/Contents/Resources/rb_main.rb:22:in `NSApplicationMain' 6 /Users/francois/Projects/fsevtest/build/Debug/fsevtest.app/Contents/Resources/rb_main.rb:22 7 /Library/Frameworks/RubyCocoa.framework/Resources/ruby/osx/objc/oc_wrapper.rb:50:in `ocm_send': Can't get Objective-C method signature for selector 'events' of receiver #<PathController:0x2297be class='PathController' id=0x534ec0> (OSX::OCMessageSendException) 8 from /Library/Frameworks/RubyCocoa.framework/Resources/ruby/osx/objc/oc_wrapper.rb:50:in `method_missing' 9 from /Users/francois/Projects/fsevtest/build/Debug/fsevtest.app/Contents/Resources/PathController.rb:27:in `choosePath' 10 from /Users/francois/Projects/fsevtest/build/Debug/fsevtest.app/Contents/Resources/rb_main.rb:22:in `NSApplicationMain' 11 from /Users/francois/Projects/fsevtest/build/Debug/fsevtest.app/Contents/Resources/rb_main.rb:22
From the obscure message, I gathered this was some kind of NoMethodError (why couldn’t they use an exception with a good name?) That was Sunday morning. Sunday evening, I suddenly had a flash that ib_outlet wouldn’t define an accessor. Changed my code to use the instance variable instead:
PathController.rb
1 if result == OSX::NSFileHandlingPanelOKButton then 2 @path.title = panel.filename 3 end
Lo and behold! It worked beautifully.