59 lines
2.1 KiB
Swift
59 lines
2.1 KiB
Swift
// (c) 2018 Daniel Galasko
|
|
// Ref: https://medium.com/over-engineering/monitoring-a-folder-for-changes-in-ios-dc3f8614f902
|
|
|
|
import Foundation
|
|
|
|
class FolderMonitor {
|
|
// MARK: Properties
|
|
|
|
/// A file descriptor for the monitored directory.
|
|
private var monitoredFolderFileDescriptor: CInt = -1
|
|
/// A dispatch queue used for sending file changes in the directory.
|
|
private let folderMonitorQueue = DispatchQueue(label: "FolderMonitorQueue", attributes: .concurrent)
|
|
/// A dispatch source to monitor a file descriptor created from the directory.
|
|
private var folderMonitorSource: DispatchSourceFileSystemObject?
|
|
/// URL for the directory being monitored.
|
|
let url: URL
|
|
|
|
var folderDidChange: (() -> Void)?
|
|
|
|
// MARK: Initializers
|
|
|
|
init(url: URL) {
|
|
self.url = url
|
|
}
|
|
|
|
// MARK: Monitoring
|
|
|
|
/// Listen for changes to the directory (if we are not already).
|
|
func startMonitoring() {
|
|
guard folderMonitorSource == nil, monitoredFolderFileDescriptor == -1 else {
|
|
return
|
|
}
|
|
// Open the directory referenced by URL for monitoring only.
|
|
monitoredFolderFileDescriptor = open(url.path, O_EVTONLY)
|
|
// Define a dispatch source monitoring the directory for additions, deletions, and renamings.
|
|
folderMonitorSource = DispatchSource.makeFileSystemObjectSource(
|
|
fileDescriptor: monitoredFolderFileDescriptor, eventMask: .write, queue: folderMonitorQueue
|
|
)
|
|
// Define the block to call when a file change is detected.
|
|
folderMonitorSource?.setEventHandler { [weak self] in
|
|
self?.folderDidChange?()
|
|
}
|
|
// Define a cancel handler to ensure the directory is closed when the source is cancelled.
|
|
folderMonitorSource?.setCancelHandler { [weak self] in
|
|
guard let strongSelf = self else { return }
|
|
close(strongSelf.monitoredFolderFileDescriptor)
|
|
strongSelf.monitoredFolderFileDescriptor = -1
|
|
strongSelf.folderMonitorSource = nil
|
|
}
|
|
// Start monitoring the directory via the source.
|
|
folderMonitorSource?.resume()
|
|
}
|
|
|
|
/// Stop listening for changes to the directory, if the source has been created.
|
|
func stopMonitoring() {
|
|
folderMonitorSource?.cancel()
|
|
}
|
|
}
|