[MacRuby] #484: scoping issues with notification center
#484: scoping issues with notification center -------------------------------------+-------------------------------------- Reporter: mattaimonetti@… | Owner: lsansonetti@… Type: defect | Status: new Priority: blocker | Milestone: MacRuby 0.5 Component: MacRuby | Keywords: -------------------------------------+-------------------------------------- Here is a reduction of a bug I encountered today: {{{ framework 'Cocoa' class Foo def dataReady(notification) puts "called ok" NSApplication.sharedApplication.terminate(nil) end end nc = NSNotificationCenter.defaultCenter # foo = nil Proc.new do foo = Foo.new task = NSTask.alloc.init pi = NSPipe.alloc.init po = NSPipe.alloc.init task.arguments = [] task.currentDirectoryPath = "/bin/" task.launchPath = "/bin/ls" task.standardInput = pi task.standardOutput = po task.launch file_handle = po.fileHandleForReading file_handle.readInBackgroundAndNotify nc.addObserver(foo, selector: "dataReady:", name: NSFileHandleReadCompletionNotification, object: file_handle) end.call app = NSApplication.sharedApplication app.delegate = self app.run }}} If you run the code as is, the observer never gets called, however if you uncomment the line defining foo before the block everything works fine. It looks like foo isn't available when the notification center tries to call it to send it the notification. -- Ticket URL: <http://www.macruby.org/trac/ticket/484> MacRuby <http://macruby.org/>
#484: scoping issues with notification center -------------------------------------+-------------------------------------- Reporter: mattaimonetti@… | Owner: lsansonetti@… Type: defect | Status: closed Priority: blocker | Milestone: Component: MacRuby | Resolution: invalid Keywords: | -------------------------------------+-------------------------------------- Changes (by lsansonetti@…): * status: new => closed * resolution: => invalid * milestone: MacRuby 0.5 => Old description:
Here is a reduction of a bug I encountered today:
{{{ framework 'Cocoa'
class Foo
def dataReady(notification) puts "called ok" NSApplication.sharedApplication.terminate(nil) end end
nc = NSNotificationCenter.defaultCenter
# foo = nil
Proc.new do
foo = Foo.new task = NSTask.alloc.init pi = NSPipe.alloc.init po = NSPipe.alloc.init
task.arguments = [] task.currentDirectoryPath = "/bin/" task.launchPath = "/bin/ls" task.standardInput = pi task.standardOutput = po task.launch
file_handle = po.fileHandleForReading file_handle.readInBackgroundAndNotify
nc.addObserver(foo, selector: "dataReady:", name: NSFileHandleReadCompletionNotification, object: file_handle)
end.call
app = NSApplication.sharedApplication app.delegate = self app.run }}}
If you run the code as is, the observer never gets called, however if you uncomment the line defining foo before the block everything works fine.
It looks like foo isn't available when the notification center tries to call it to send it the notification.
New description: Here is a reduction of a bug I encountered today: {{{ framework 'Cocoa' class Foo def dataReady(notification) puts "called ok" NSApplication.sharedApplication.terminate(nil) end end nc = NSNotificationCenter.defaultCenter # foo = nil Proc.new do foo = Foo.new task = NSTask.alloc.init pi = NSPipe.alloc.init po = NSPipe.alloc.init task.arguments = [] task.currentDirectoryPath = "/bin/" task.launchPath = "/bin/ls" task.standardInput = pi task.standardOutput = po task.launch file_handle = po.fileHandleForReading file_handle.readInBackgroundAndNotify nc.addObserver(foo, selector: "dataReady:", name: NSFileHandleReadCompletionNotification, object: file_handle) end.call app = NSApplication.sharedApplication app.delegate = self app.run }}} If you run the code as is, the observer never gets called, however if you uncomment the line defining foo before the block everything works fine. It looks like foo isn't available when the notification center tries to call it to send it the notification. -- Comment: NSNotificationCenter doesn't retain the observer. In your example, foo is garbage collected before the notification. You must keep a live reference to foo. This is a common Cocoa pattern. Observers, delegates & friends are always weakly referenced. -- Ticket URL: <http://www.macruby.org/trac/ticket/484#comment:1> MacRuby <http://macruby.org/>
#484: scoping issues with notification center -------------------------------------+-------------------------------------- Reporter: mattaimonetti@… | Owner: lsansonetti@… Type: defect | Status: closed Priority: blocker | Milestone: Component: MacRuby | Resolution: invalid Keywords: | -------------------------------------+-------------------------------------- Comment(by mattaimonetti@…): ok... while I understand (and wish the doc would mention that), this is really annoying. In real life, here is what I was doing: looping through a list of items and create a pipe and add a notification for it. I guess in obj-c I would use retain on the object, but I believe I can't in MacRuby. What options do I currently without having to do some weird ruby stuff like creating an array outside the loop and add items to it :( - Matt -- Ticket URL: <http://www.macruby.org/trac/ticket/484#comment:2> MacRuby <http://macruby.org/>
#484: scoping issues with notification center -------------------------------------+-------------------------------------- Reporter: mattaimonetti@… | Owner: lsansonetti@… Type: defect | Status: closed Priority: blocker | Milestone: Component: MacRuby | Resolution: invalid Keywords: | -------------------------------------+-------------------------------------- Comment(by lsansonetti@…): It's actually documented. http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundat... "Important: The notification center does not retain its observers, therefore, you must ensure that you unregister observers (using removeObserver: or removeObserver:name:object:) before they are deallocated. (If you don't, you will generate a runtime error if the center sends a message to a freed object.)" MacRuby uses Objective-C in GC mode so retain will not help since it's a no-op. You must keep a reference to the observer by yourself. Typically this isn't such a problem in Cocoa apps since the observer is generally a controller object (self). Maybe you should re-design your program. -- Ticket URL: <http://www.macruby.org/trac/ticket/484#comment:3> MacRuby <http://macruby.org/>
participants (1)
-
MacRuby