2012-10-27 13 views
4

我正在使用MacRuby中的GUI應用程序,我需要使用FSEvents。我正在爲不同的目錄註冊幾個流。任何這些目錄中的更改都會導致運行回調,但存在一個大問題:無論更改哪個目錄,都會執行最後一次註冊的回調。MacRuby中的FSEvents:執行錯誤的回調

下面是獨立的測試腳本:

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 

當我運行它,並開始修改這些目錄:

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

輸出爲:

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

我寧願預計是:

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

也許我可以通過提供我需要的數據通過上下文參數來解決此問題(因爲檢查paths內部回調揭示實際更改的目錄),但仍然,目前的行爲對我來說是完全意外的。我使用OS X 10.8.2(12C60)和MacRuby 0.12(ruby 1.9.2)[universal-darwin10.0,x86_64]。

回答

0

是的,這真的很奇怪。我也有這種行爲。似乎最新的註冊回調總是被調用。但好的一面是,從第四個參數到回調函數有可能獲得實際調用目錄的路徑。我必須使用這樣的構造。

我不是一個紅寶石主義者,但是這段代碼適合我。

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 

這裏的輸出我看到:

[email protected] ~/local/fsync 
$ macruby fsevents.rb & 
[1] 14638 

[email protected] ~/local/fsync 
$ touch dir1/mao 

[email protected] ~/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

謝謝!很高興知道我不是唯一遇到這個問題的人。解決方法看起來不錯。 –