Skip to content

Instantly share code, notes, and snippets.

@fpiraneo
Created July 15, 2020 10:02
Show Gist options
  • Save fpiraneo/9fa35b82e8f54374be83e7fc5430d467 to your computer and use it in GitHub Desktop.
Save fpiraneo/9fa35b82e8f54374be83e7fc5430d467 to your computer and use it in GitHub Desktop.
/*
Copyright (C) 2016 Apple Inc. All Rights Reserved.
See LICENSE.txt for this sample’s licensing information
Partially modified by Francesco Piraneo G.
Original url: https://github.com/robovm/apple-ios-samples/blob/master/ListerforwatchOSiOSandOSX/Swift/ListerKit/DirectoryMonitor.swift
Abstract:
`DirectoryMonitor` is used to monitor the contents of the provided directory by using a GCD dispatch source.
*/
import Foundation
/// A protocol that allows delegates of `DirectoryMonitor` to respond to changes in a directory.
protocol DirectoryMonitorDelegate: class {
func directoryMonitorDidObserveChange(directoryMonitor: DirectoryMonitor)
}
class DirectoryMonitor {
// MARK: Properties
/// The `DirectoryMonitor`'s delegate who is responsible for responding to `DirectoryMonitor` updates.
weak var delegate: DirectoryMonitorDelegate?
/// A file descriptor for the monitored directory.
private var monitoredDirectoryFileDescriptor: CInt = -1
/// A dispatch queue used for sending file changes in the directory.
private let directoryMonitorQueue = DispatchQueue(label: "ch.zriemann.AnoniCloud-Connect.DirectoryMonitor", attributes: .concurrent)
/// A dispatch source to monitor a file descriptor created from the directory.
private var directoryMonitorSource: DispatchSource?
/// URL for the directory being monitored.
private var url: URL?
// MARK: Monitoring
func startMonitoring(_ url: URL) {
// Listen for changes to the directory (if we are not already).
if directoryMonitorSource == nil && monitoredDirectoryFileDescriptor == -1 {
// Save actual monitoring URL
self.url = url
// Open the directory referenced by URL for monitoring only.
monitoredDirectoryFileDescriptor = open((url as NSURL).fileSystemRepresentation, O_EVTONLY)
// Define a dispatch source monitoring the directory for additions, deletions, and renamings.
directoryMonitorSource = DispatchSource.makeFileSystemObjectSource(fileDescriptor: monitoredDirectoryFileDescriptor, eventMask: DispatchSource.FileSystemEvent.write, queue: directoryMonitorQueue) as? DispatchSource
// Define the block to call when a file change is detected.
directoryMonitorSource?.setEventHandler{
// Call out to the `DirectoryMonitorDelegate` so that it can react appropriately to the change.
self.delegate?.directoryMonitorDidObserveChange(directoryMonitor: self)
}
// Define a cancel handler to ensure the directory is closed when the source is cancelled.
directoryMonitorSource?.setCancelHandler{
close(self.monitoredDirectoryFileDescriptor)
self.monitoredDirectoryFileDescriptor = -1
self.directoryMonitorSource = nil
}
// Start monitoring the directory via the source.
directoryMonitorSource?.resume()
} else {
directoryMonitorSource?.cancel()
startMonitoring(url)
}
}
func stopMonitoring() {
// Stop listening for changes to the directory, if the source has been created.
if directoryMonitorSource != nil {
// Stop monitoring the directory via the source.
directoryMonitorSource?.cancel()
url = nil
}
}
func getMonitoringURL() -> String {
return self.url?.absoluteString ?? "NO URL MONITORED"
}
}
@fpiraneo
Copy link
Author

fpiraneo commented Jul 15, 2020

This is a partially modified macOS directory monitor published by Apple during WWDC 2016.
You can find original Apple version at: Original Apple DirectoryMonitor
Original version cannot smootly stop and restart monitoring on a different directory. I've tested my modified version it and it's working. Feel free to contact me here if you have suggestions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment