0

Is there an alternative to fsevent or some kind of wrapper for it?

I'm trying to monitor a specific folder for changes to files with a certain extension.

AWF4vk
  • 5,810
  • 3
  • 37
  • 70
  • possible duplicate of [Observe a File or Folder in Objective-C](http://stackoverflow.com/questions/1386743/observe-a-file-or-folder-in-objective-c) – Rob Keniger Aug 27 '11 at 02:59
  • @Rob Keniger: Not a duplicate of that question, since that one doesn't exclude FSEvents and, in fact, FSEvents (which you suggested on that question) is the accepted answer. – Peter Hosey Aug 27 '11 at 03:51

2 Answers2

4

There is UKKQueue, which is a nice wrapper for kernel queue event monitoring - the alternative mentioned in the documentation.

Peter Hosey
  • 95,783
  • 15
  • 211
  • 370
Joshua Nozzi
  • 60,946
  • 14
  • 140
  • 135
  • @Peter Heh. Thanks for the edit. I started writing, got sidetracked, then came back to it without proof reading. :-) – Joshua Nozzi Aug 27 '11 at 14:27
  • 4
    Looks like VDKQueue is an updated version of UKKQueue (which is 8 years old). https://github.com/bdkjones/VDKQueue – Joel May 04 '12 at 06:23
1

These days you can use GCD to monitor folders without any other dependencies:

import Foundation

@objc public class DirectoryWatcher : NSObject {
    override public init() {
        super.init()
    }
    
    deinit {
        stop()
    }
    
    public typealias Callback = (_ directoryWatcher: DirectoryWatcher) -> Void
    
    @objc public convenience init(withPath path: String, callback: @escaping Callback) {
        self.init()
        if !watch(path: path, callback: callback) {
            assert(false)
        }
    }
    
    private var dirFD : Int32 = -1 {
        didSet {
            if oldValue != -1 {
                close(oldValue)
            }
        }
    }
    private var dispatchSource : DispatchSourceFileSystemObject?
    
    @objc public func watch(path: String, callback: @escaping Callback) -> Bool {
        // Open the directory
        dirFD = open(path, O_EVTONLY)
        if dirFD < 0 {
            return false
        }
        
        // Create and configure a DispatchSource to monitor it
        let dispatchSource = DispatchSource.makeFileSystemObjectSource(fileDescriptor: dirFD, eventMask: .write, queue: DispatchQueue.main)
        dispatchSource.setEventHandler {[unowned self] in
            callback(self)
        }
        dispatchSource.setCancelHandler {[unowned self] in
            self.dirFD = -1
        }
        self.dispatchSource = dispatchSource

        // Start monitoring
        dispatchSource.resume()
        
        // Success
        return true
    }

    @objc public func stop() {
        // Leave if not monitoring
        guard let dispatchSource = dispatchSource else {
            return
        }
        
        // Don't listen to more events
        dispatchSource.setEventHandler(handler: nil)
        
        // Cancel the source (this will also close the directory)
        dispatchSource.cancel()
        self.dispatchSource = nil
    }
}

Use it like Apple's DirectoryWatcher example, something like this:

let directoryWatcher = DirectoryWatcher(withPath: "/path/to/the/folder/you/want/to/monitor/", callback: {
    print("the folder changed")
})

Destroying the object will stop watching, or you can stop it explicitly

directoryWatcher.stop()

It should be compatible with Objective C they way it's written (untested). Using it would be like this:

DirectoryWatcher *directoryWatcher = [DirectoryWatcher.alloc initWithPath: @"/path/to/the/folder/you/want/to/monitor/" callback: ^(DirectoryWatcher *directoryWatcher) {
    NSLog(@"the folder changed")
}];

Stopping it is similar

[directoryWatcher stop];
John Stephen
  • 7,625
  • 2
  • 31
  • 45