【问题标题】:FSEvents in MacRuby: wrong callback is executedMacRuby中的FSEvents:执行错误的回调
【发布时间】:2012-10-17 16:30:47
【问题描述】:

我正在 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]。

【问题讨论】:

    标签: ruby macos macruby fsevents


    【解决方案1】:

    是的,这真的很奇怪。我也有这种行为。似乎总是调用最新注册的回调。但从好的方面来说,可以从回调的第四个参数获取到实际调用的目录的路径。我不得不使用这样的构造。

    我不是一个 ruby​​ist,但这段代码对我有用。

    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"
    

    【讨论】:

    • 谢谢!很高兴知道我不是唯一遇到此问题的人。解决方法看起来不错。
    猜你喜欢
    • 2020-08-29
    • 2015-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-23
    • 2020-05-28
    相关资源
    最近更新 更多