FSEvents on MacRuby: Invalid callback performed

I am working on a graphical interface in MacRuby and I need to use FSEvents. I am registering a couple of threads for different directories. Changes to any of these directories trigger a callback, but there is a big problem: no matter which directory changes, the last registered callback is executed.

Below is an isolated test script:

framework 'Cocoa' framework 'CoreServices' class Monitor def initialize(dir) @dir = dir end def start(&block) callback = Proc.new do |stream, context, count, paths, flags, ids| p @dir block.call end flags = KFSEventStreamCreateFlagUseCFTypes @stream = FSEventStreamCreate(KCFAllocatorDefault, callback, nil, [@dir], KFSEventStreamEventIdSinceNow, 0.0, flags) FSEventStreamScheduleWithRunLoop(@stream, CFRunLoopGetCurrent(), KCFRunLoopDefaultMode) FSEventStreamStart(@stream) end end Monitor.new(Dir.pwd + "/dir1").start { p "dir1" } Monitor.new(Dir.pwd + "/dir2").start { p "dir2" } Monitor.new(Dir.pwd + "/dir3").start { p "dir3" } app = NSApplication.sharedApplication app.run 

When I started it and started changing these directories:

 ~/tmp/fsevents $ touch dir1/test ~/tmp/fsevents $ touch dir2/test ~/tmp/fsevents $ touch dir3/test 

output:

 "/Users/janek/tmp/fsevents/dir3" "dir3" "/Users/janek/tmp/fsevents/dir3" "dir3" "/Users/janek/tmp/fsevents/dir3" "dir3" 

I would prefer:

 "/Users/janek/tmp/fsevents/dir1" "dir1" "/Users/janek/tmp/fsevents/dir2" "dir2" "/Users/janek/tmp/fsevents/dir3" "dir3" 

Perhaps I could get around this problem by providing the data I need through a context argument (because checking the paths inside the callback shows the directory actually changed), but still the current behavior is completely unexpected for me.

I am using OS X 10.8.2 (12C60) and MacRuby 0.12 (ruby 1.9.2) [universal-darwin10.0, x86_64].

+4
source share
1 answer

Yes, this is really strange. I also have this behavior. It seems that the last registered callback is always called. But on the bright side, from the fourth argument to the callback, you can get the path to the directory that really received the call. I had to use such a design.

I don't really look like a rubista, but this code works for me.

 framework 'Cocoa' framework 'CoreServices' class Monitor @@registry = {} def self.register(dir, other_data) @@registry[dir] = other_data end def initialize(dir, other_data) @dir = dir self.class.register(dir, other_data) callback = Proc.new do |stream, context, count, paths, flags, ids| paths.cast!('*') p "the callback that triggered has closure variable @dir=#{@dir}" p "but the actual callback said the dir was #{paths[0]}" p "the metadata that I stored associated with that directory is #{@@registry[paths[0]]}" end @stream = FSEventStreamCreate(KCFAllocatorDefault, callback, nil, [@dir], KFSEventStreamEventIdSinceNow, 0.0, 0) FSEventStreamScheduleWithRunLoop(@stream, CFRunLoopGetCurrent(), KCFRunLoopDefaultMode) FSEventStreamStart(@stream) end end Monitor.new(Dir.pwd + "/dir1/", 'dir1 data') Monitor.new(Dir.pwd + "/dir2/", 'dir2 data') Monitor.new(Dir.pwd + "/dir3/", 'dir3 data') app = NSApplication.sharedApplication app.run 

Here I see the output:

 rmcgibbo@Roberts-MacBook-Pro-2 ~/local/fsync $ macruby fsevents.rb & [1] 14638 rmcgibbo@Roberts-MacBook-Pro-2 ~/local/fsync $ touch dir1/mao rmcgibbo@Roberts-MacBook-Pro-2 ~/local/fsync $ "the callback that triggered has closure variable @dir=/Users/rmcgibbo/local/fsync/dir3/" "but the actual callback said the dir was /Users/rmcgibbo/local/fsync/dir1/" "the metadata that I stored associated with that directory is dir1 data" 
0
source

Source: https://habr.com/ru/post/1442528/


All Articles