A huge advantage of Cocoa over AppleScript is the presence of callbacks and notifications.
Here is a smarter way to monitor the directory. No timers, no loops.
FSEvents notify every time the directory changes, the callback invokes a delegate method (directoryDidChange) in the script.
First, create an Objective-C class in your project (⌘N), name it FSEDirectoryWatcher (subclass of NSObject)
Replace the contents of FSEDirectoryWatcher.h with
#import <Foundation/Foundation.h>
@class FSEDirectoryWatcher;
@protocol FSEDirectoryWatcherDelegate
- (void)directoryDidChange:(NSString *)path;
@end
@interface FSEDirectoryWatcher : NSObject
+ (id)directoryWatcherWithPath:(NSString *)path delegate:(id)delegate;
- (id)initWithPath:(NSString *)path delegate:(id)delegate;
- (void)start;
- (void)stop;
@property (copy) NSString *directory;
@property (weak) id<FSEDirectoryWatcherDelegate> delegate;
@end
Replace the contents of FSEDirectoryWatcher.m with
#import "FSEDirectoryWatcher.h"
static void fileSystemEventCallback(ConstFSEventStreamRef streamRef, void *userData, size_t numEvents, void *eventPaths,
const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]);
@interface FSEDirectoryWatcher ()
{
dispatch_queue_t queue;
FSEventStreamRef stream;
}
@end
@implementation FSEDirectoryWatcher
+ (id)directoryWatcherWithPath:(NSString *)path delegate:(id)delegate
{
return [[FSEDirectoryWatcher alloc] initWithPath:path delegate];
}
- (id)initWithPath:(NSString *)path delegate:(id)delegate
{
self = [super init];
if (self) {
_directory = path;
_delegate = delegate;
queue = dispatch_queue_create("com.myself.FSEDirectoryWatcher", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void) dealloc
{
if (queue) dispatch_release(queue);
[self stop];
}
- (void)start
{
NSArray *pathsToWatch = @[self.directory];
FSEventStreamContext context = {0, (__bridge void *)self, NULL, NULL, NULL};
CFAbsoluteTime latency = 3.0; /* Latency in seconds */
stream = FSEventStreamCreate(NULL, &fileSystemEventCallback, &context, (__bridge CFArrayRef)pathsToWatch,
kFSEventStreamEventIdSinceNow, latency, kFSEventStreamCreateFlagUseCFTypes);
FSEventStreamSetDispatchQueue(stream, queue);
FSEventStreamStart(stream);
}
- (void)stop
{
if (stream) {
FSEventStreamStop(stream);
FSEventStreamInvalidate(stream);
FSEventStreamRelease(stream);
stream = nil;
}
}
@end
static void fileSystemEventCallback(ConstFSEventStreamRef streamRef, void *userData, size_t numEvents, void *eventPaths,
const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) {
FSEDirectoryWatcher *directoryWatcher = (__bridge FSEDirectoryWatcher *)userData;
NSArray *paths = (__bridge NSArray *)eventPaths;
[paths enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (directoryWatcher.delegate) [directoryWatcher.delegate directoryDidChange:obj];
}];
}
Note: the FSEDirectoryWatcher class requires ARC (automatic reference counting)
This is the AppleScript code
property DirectoryWatcher : class "FSEDirectoryWatcher"
property statusImage1 : missing value -- image view 1
property statusImage2 : missing value -- image view 2
on applicationWillFinishLaunching_(aNotification)
set hotFolder to current application's NSString's stringWithString_("/Path/to/directory")
directoryDidChange_(hotFolder)
set watcher to DirectoryWatcher's directoryWatcherWithPath_delegate_(hotFolder, me)
watcher's start()
end applicationWillFinishLaunching_
on imageForStatus_(status)
if status = true then
set imageName to current application's NSImageNameStatusAvailable
else
set imageName to current application's NSImageNameStatusUnavailable
end if
return current application's NSImage's imageNamed_(imageName)
end imageForStatus_
on directoryDidChange_(directoryPath)
set filePath to directoryPath's stringByAppendingPathComponent_("logfile1.log")
set fileExists to NSFileManager's defaultManager()'s fileExistsAtPath_(filePath) as boolean
statusImage1's setImage_(imageForStatus_(fileExists))
set filePath to directoryPath's stringByAppendingPathComponent_("logfile2.log")
set fileExists to NSFileManager's defaultManager()'s fileExistsAtPath_(filePath) as boolean
statusImage2's setImage_(imageForStatus_(fileExists))
end directoryDidChange_