Programming Cocoa With MacRuby: Part One
- January 5th, 2010
- Posted in Coding . Ruby . cocoa
- By lastobelus
- Write comment
The next sample has a little wrinkle. Here is the first port:
statusbar-item.rb (status item disappears)
#!/usr/bin/env macruby
framework 'cocoa'
class App
def applicationDidFinishLaunching(aNotification)
statusbar = NSStatusBar.systemStatusBar
status_item = statusbar.statusItemWithLength(NSVariableStatusItemLength)
image = NSImage.alloc.initWithContentsOfFile("stretch.tiff")
raise "Icon file 'stretch.tiff' is missing." unless image
status_item.setImage(image)
end
end
NSApplication.sharedApplication
NSApp.delegate = App.new
NSApp.run
However, this does not quite work as expected. After briefly appearing, the status_item disappears. Now, in objective c one would have to explicitly retain the result of statusItemWithLength, so I assumed this was the local variable status_item getting garbage collected.
Sure enough, if we change it to @status_item (which will then live for the life of the App object, not just the duration of applicationDidFinishLaunching), it works fine.
However I also noticed that adding a “sleep 1″ to the end of applicationDidFinishLaunching makes it work as well, with status_item as a local variable. I was not really sure why this would be, so I posted it to the Macruby dev list, and this is what Laurent replied:
I believe the reason is because your sleep 1 prevented a non-deterministic garbage collection cycle. In the presence of a Cocoa run loop the GC might be triggered by a few different ways. I believe you’re just lucky that it works
![]()
In my opinion the Macruby behaviour (without the sleep) is better: the status item really should disappear when it goes out of scope. The reason it doesn’t in the rubycocoa example is because rubycocoa does a retain behind the scenes, so although the ruby variable pointing at the status item goes out of scope, the status item itself does not.
statusbar-item.rb (works)
#!/usr/bin/env macruby
framework 'cocoa'
class App
def applicationDidFinishLaunching(aNotification)
statusbar = NSStatusBar.systemStatusBar
@status_item = statusbar.statusItemWithLength(NSVariableStatusItemLength)
image = NSImage.new.initWithContentsOfFile("stretch.tiff")
raise "Icon file 'stretch.tiff' is missing." unless image
@status_item.setImage(image)
end
end
NSApplication.sharedApplication
NSApp.delegate = App.new
NSApp.run




No comments yet.