#import
@class DirectoryWatcher;
@protocol DirectoryWatcherDelegate
@required
- (void)directoryDidChange:(DirectoryWatcher *)folderWatcher;
@end
@interface DirectoryWatcher : NSObject
{
id <</span>DirectoryWatcherDelegate
int dirFD;
CFFileDescriptorRef dirKQRef;
}
@property (nonatomic, assign) id <</span>DirectoryWatcherDelegate
+ (DirectoryWatcher *)watchFolderWithPath:(NSString *)watchPath delegate:(id<<span style="color: #4f8187">DirectoryWatcherDelegate
- (void)invalidate;
@end
#import "DirectoryWatcher.h"
#include
#include
#include
#include
#include
#import
@interface DirectoryWatcher (DirectoryWatcherPrivate)
- (BOOL)startMonitoringDirectory
- (void)kqueueFired;
@end
#pragma mark -
@implementation DirectoryWatcher
@synthesize delegate;
- (id)init
{
self= [super init];
delegate = NULL;
dirFD = -1;
dirKQRef = NULL;
return self;
}
- (void)dealloc
{
[self invalidate];
[super dealloc];
}
+ (DirectoryWatcher *)watchFolderWithPath:(NSString *)watchPath delegate:(id)watchDelegate
{
DirectoryWatcher *retVal = NULL;
if ((watchDelegate != NULL) && (watchPath != NULL))
{
DirectoryWatcher *tempManager = [[[DirectoryWatcher alloc] init] autorelease];
tempManager.delegate = watchDelegate;
if ([tempManager startMonitoringDirectory
{
// Everything appears to be in order, so return the DirectoryWatcher.
// Otherwise we'll fall through and return NULL.
retVal = tempManager;
}
}
return retVal;
}
- (void)invalidate
{
if (dirKQRef != NULL)
{
CFFileDescriptorInvalida
CFRelease(dirKQRef);
dirKQRef = NULL;
// We don't need to close the kq, CFFileDescriptorInvalida
// Change the value so no one thinks it's still live.
kq = -1;
}
if(dirFD != -1)
{
close(dirFD);
dirFD = -1;
}
}
@end
#pragma mark -
@implementation DirectoryWatcher (DirectoryWatcherPrivate)
- (void)kqueueFired
{
// call our delegate of the directory change
}
static void KQCallback(CFFileDescriptorRef kqRef, CFOptionFlags callBackTypes, void *info)
{
}
- (BOOL)startMonitoringDirectory
{
// Double initializing is not going to work...
if ((dirKQRef == NULL) && (dirFD == -1) && (kq == -1))
{
// Open the directory we're going to watch
dirFD = open([dirPath fileSystemRepresentation
if (dirFD >= 0)
{
// Create a kqueue for our event messages...
kq = kqueue();
if (kq >= 0)
{
struct kevent eventToAdd;
eventToAdd.ident
eventToAdd.filter = EVFILT_VNODE;
eventToAdd.flags
eventToAdd.fflags = NOTE_WRITE;
eventToAdd.data
eventToAdd.udata
int errNum = kevent(kq, &eventToAdd, 1, NULL, 0, NULL);
if (errNum == 0)
{
CFFileDescriptorContext context = { 0, self, NULL, NULL, NULL };
CFRunLoopSourceRef
// Passing true in the third argument so CFFileDescriptorInvalida
dirKQRef = CFFileDescriptorCreate(NULL, kq, true, KQCallback, &context);
if (dirKQRef != NULL)
{
rls = CFFileDescriptorCreateRu
if (rls != NULL)
{
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
CFFileDescriptorEnableCa
// If everything worked, return early and bypass shutting things down
return YES;
}
// Couldn't create a runloop source, invalidate and release the CFFileDescriptorRef
CFFileDescriptorInvalida
dirKQRef = NULL;
}
}
// kq is active, but something failed, close the handle...
close(kq);
kq = -1;
}
// file handle is open, but something failed, close the handle...
close(dirFD);
dirFD = -1;
}
}
return NO;
}
@end