4

私は MacRuby で GUI アプリに取り組んでおり、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] を使用しています。

4

1 に答える 1

0

ええ、これは本当に奇妙です。私もこの癖があります。最後に登録されたコールバックが常に呼び出されるようです。しかし明るい面としては、コールバックへの 4 番目の引数から、実際に呼び出されたディレクトリへのパスを取得することが可能です。このような構成を使用する必要がありました。

私はあまりルビストではありませんが、このコードはうまくいきます。

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

これが私が見る出力です:

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"
于 2012-11-18T12:46:34.227 に答える