Skip to content

Commit

Permalink
Added DTFolderMonitor and integrated in DTZipArchive Demo
Browse files Browse the repository at this point in the history
  • Loading branch information
odrobnik committed Aug 5, 2013
1 parent a3bcb18 commit 43e9913
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 10 deletions.
48 changes: 48 additions & 0 deletions Core/Source/DTFolderMonitor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// DTFolderMonitor.h
// DTFoundation
//
// Created by Oliver Drobnik on 05.08.13.
// Copyright (c) 2013 Cocoanetics. All rights reserved.
//

// The block to execute if a monitored folder changes
typedef void (^DTFolderMonitorBlock) (void);

/**
Class for monitoring changes on a folder. This can be used to monitor the application documents folder for changes in the files there if the user adds or removes files via iTunes file sharing.
*/

@interface DTFolderMonitor : NSObject

/**
@name Creating a Folder Monitor
*/

/**
Creates a new DTFolderMonitor to watch the folder at the given URL. Whenever there is a change on this folder the block is executed.
The URL must be a file URL. Both the URL and the block parameter are mandatory. The block is being dispatched on a background queue.
@param URL The monitored folder URL
@param block The block to execute if the folder is being modified
@returns The instantiated monitor in suspended mode. Call -startMonitoring to start monitoring.
*/
+ (DTFolderMonitor *)folderMonitorForURL:(NSURL *)URL block:(DTFolderMonitorBlock)block;


/**
@name Starting/Stopping Monitoring
*/

/**
Start monitoring the folder. A monitor can be started and stopped multiple times.
*/
- (void)startMonitoring;

/**
Stop monitoring the folder. A monitor can be started and stopped multiple times.
*/
- (void)stopMonitoring;

@end
106 changes: 106 additions & 0 deletions Core/Source/DTFolderMonitor.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
//
// DTFolderMonitor.m
// DTFoundation
//
// Created by Oliver Drobnik on 05.08.13.
// Copyright (c) 2013 Cocoanetics. All rights reserved.
//

#import "DTFolderMonitor.h"

@implementation DTFolderMonitor
{
NSURL *_URL;
DTFolderMonitorBlock _block;

int _fileDescriptor;
dispatch_queue_t _queue;
dispatch_source_t _source;
}

+ (DTFolderMonitor *)folderMonitorForURL:(NSURL *)URL block:(DTFolderMonitorBlock)block
{
return [[DTFolderMonitor alloc] initWithURL:URL block:block];
}

- (instancetype)initWithURL:(NSURL *)URL block:(DTFolderMonitorBlock)block
{
NSParameterAssert(URL);
NSParameterAssert(block);
NSAssert([URL isFileURL], @"URL Parameter must be a folder URL");

self = [super init];

if (self)
{
_URL = URL;
_block = [block copy];

NSString *path = [_URL path];
_fileDescriptor = open([path fileSystemRepresentation], O_EVTONLY);

if (!_fileDescriptor)
{
return nil;
}

_queue = dispatch_queue_create("DTFolderMonitor Queue", 0);
}

return self;
}

- (void)dealloc
{
[self stopMonitoring];

#if OS_OBJECT_USE_OBJC
dispatch_release(_queue);
#endif
}

- (void)startMonitoring
{
@synchronized(self)
{
if (_source)
{
return;
}

// watch the file descriptor for writes
_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, _fileDescriptor, DISPATCH_VNODE_WRITE, _queue);

// call the passed block if the source is modified
dispatch_source_set_event_handler(_source, _block);

// close the file descriptor when the dispatch source is cancelled
dispatch_source_set_cancel_handler(_source, ^{

close(_fileDescriptor);
});

// at this point the dispatch source is paused, so start watching
dispatch_resume(_source);
}
}

- (void)stopMonitoring
{
@synchronized(self)
{
if (!_source)
{
return;
}

dispatch_source_cancel(_source);

#if !OS_OBJECT_USE_OBJC
dispatch_release(_source);
#endif
_source = nil;
}
}

@end
25 changes: 19 additions & 6 deletions DTFoundation.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,12 @@
A77DD42614E825FC00F34B03 /* zip.h in Headers */ = {isa = PBXBuildFile; fileRef = A77DD41514E825FC00F34B03 /* zip.h */; settings = {ATTRIBUTES = (Public, ); }; };
A77DD42714E825FC00F34B03 /* zip.h in Headers */ = {isa = PBXBuildFile; fileRef = A77DD41514E825FC00F34B03 /* zip.h */; };
A78220BB168060CA005B602D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A7F4DFFA147FD08F00F4059A /* Foundation.framework */; };
A78D661D17AFFCCC0039F5E6 /* DTFolderMonitor.h in Headers */ = {isa = PBXBuildFile; fileRef = A78D661B17AFFCCC0039F5E6 /* DTFolderMonitor.h */; };
A78D661E17AFFCCC0039F5E6 /* DTFolderMonitor.h in Headers */ = {isa = PBXBuildFile; fileRef = A78D661B17AFFCCC0039F5E6 /* DTFolderMonitor.h */; };
A78D661F17AFFCCC0039F5E6 /* DTFolderMonitor.h in Headers */ = {isa = PBXBuildFile; fileRef = A78D661B17AFFCCC0039F5E6 /* DTFolderMonitor.h */; };
A78D662017AFFCCC0039F5E6 /* DTFolderMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = A78D661C17AFFCCC0039F5E6 /* DTFolderMonitor.m */; };
A78D662117AFFCCC0039F5E6 /* DTFolderMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = A78D661C17AFFCCC0039F5E6 /* DTFolderMonitor.m */; };
A78D662217AFFCCC0039F5E6 /* DTFolderMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = A78D661C17AFFCCC0039F5E6 /* DTFolderMonitor.m */; };
A79231CE157A0B9400C3ACBB /* NSURL+DTUnshorten.h in Headers */ = {isa = PBXBuildFile; fileRef = A79231CC157A0B9400C3ACBB /* NSURL+DTUnshorten.h */; settings = {ATTRIBUTES = (Public, ); }; };
A79231CF157A0B9400C3ACBB /* NSURL+DTUnshorten.h in Headers */ = {isa = PBXBuildFile; fileRef = A79231CC157A0B9400C3ACBB /* NSURL+DTUnshorten.h */; };
A79231D0157A0B9400C3ACBB /* NSURL+DTUnshorten.m in Sources */ = {isa = PBXBuildFile; fileRef = A79231CD157A0B9400C3ACBB /* NSURL+DTUnshorten.m */; };
Expand Down Expand Up @@ -602,6 +608,8 @@
A77DD41514E825FC00F34B03 /* zip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zip.h; sourceTree = "<group>"; };
A78220BA168060CA005B602D /* libDTUTI_iOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libDTUTI_iOS.a; sourceTree = BUILT_PRODUCTS_DIR; };
A7859D3D16DF8D180076F2DB /* AppledocSettings.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = AppledocSettings.plist; sourceTree = "<group>"; };
A78D661B17AFFCCC0039F5E6 /* DTFolderMonitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTFolderMonitor.h; sourceTree = "<group>"; };
A78D661C17AFFCCC0039F5E6 /* DTFolderMonitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTFolderMonitor.m; sourceTree = "<group>"; };
A78EDD1717A65AD700480205 /* DTScriptExpression.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DTScriptExpression.h; sourceTree = "<group>"; };
A78EDD1817A65AD700480205 /* DTScriptExpression.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DTScriptExpression.m; sourceTree = "<group>"; };
A78EDD1917A65AD700480205 /* DTScriptVariable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DTScriptVariable.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1346,6 +1354,8 @@
A77D5BF916E4961A00A45C28 /* DTBase64Coding.m */,
A7D6F2E315063448001CACDD /* DTExtendedFileAttributes.h */,
A7D6F2E415063448001CACDD /* DTExtendedFileAttributes.m */,
A78D661B17AFFCCC0039F5E6 /* DTFolderMonitor.h */,
A78D661C17AFFCCC0039F5E6 /* DTFolderMonitor.m */,
A70B4CC71486621B00873A4A /* DTVersion.h */,
A70B4CC81486621B00873A4A /* DTVersion.m */,
A7FB1218175C9D5000D4B7F0 /* DTWeakSupport.h */,
Expand Down Expand Up @@ -1584,6 +1594,7 @@
A7C92B6A174F9AEC0019D70A /* UIViewController+DTSidePanelController.h in Headers */,
A7FB1216175C9C8B00D4B7F0 /* DTSidePanelController.h in Headers */,
A7FB121A175C9D5000D4B7F0 /* DTWeakSupport.h in Headers */,
A78D661E17AFFCCC0039F5E6 /* DTFolderMonitor.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -1606,6 +1617,7 @@
A77D5BFC16E4961A00A45C28 /* DTBase64Coding.h in Headers */,
A7FB121B175C9D5000D4B7F0 /* DTWeakSupport.h in Headers */,
A70C4FFB17AA7F7D00000DF5 /* DTUtils.h in Headers */,
A78D661F17AFFCCC0039F5E6 /* DTFolderMonitor.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1664,6 +1676,7 @@
A70C4FFE17AA7F9C00000DF5 /* DTActionSheet.h in Headers */,
A70C4FFF17AA7F9C00000DF5 /* DTAlertView.h in Headers */,
A70C500017AA7F9C00000DF5 /* UIView+DTActionHandlers.h in Headers */,
A78D661D17AFFCCC0039F5E6 /* DTFolderMonitor.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -2238,6 +2251,7 @@
A70C4FEA17AA7F0200000DF5 /* NSScanner+DTScripting.m in Sources */,
A70C4FF117AA7F2000000DF5 /* DTObjectBlockExecutor.m in Sources */,
A70C4FF217AA7F2000000DF5 /* NSObject+DTRuntime.m in Sources */,
A78D662117AFFCCC0039F5E6 /* DTFolderMonitor.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -2282,6 +2296,7 @@
A70C4FF017AA7F0700000DF5 /* NSScanner+DTScripting.m in Sources */,
A70C4FF517AA7F2300000DF5 /* DTObjectBlockExecutor.m in Sources */,
A70C4FF617AA7F2300000DF5 /* NSObject+DTRuntime.m in Sources */,
A78D662217AFFCCC0039F5E6 /* DTFolderMonitor.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -2359,6 +2374,7 @@
A70C4FED17AA7F0300000DF5 /* NSScanner+DTScripting.m in Sources */,
A70C4FF317AA7F2100000DF5 /* DTObjectBlockExecutor.m in Sources */,
A70C4FF417AA7F2100000DF5 /* NSObject+DTRuntime.m in Sources */,
A78D662017AFFCCC0039F5E6 /* DTFolderMonitor.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -3328,17 +3344,15 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_WARN_EMPTY_BODY = YES;
CODE_SIGN_IDENTITY = "iPhone Developer: Stefan Gugarel (5V5NEAJJ6M)";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Stefan Gugarel (5V5NEAJJ6M)";
CODE_SIGN_IDENTITY = "iPhone Developer";
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Demo/DTZipArchiveDemo/DTZipArchiveDemo-Prefix.pch";
INFOPLIST_FILE = "Demo/DTZipArchiveDemo/DTZipArchiveDemo-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 6.1;
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = DTZipArchive;
PROVISIONING_PROFILE = "EE8FE43F-35E0-4192-91C6-0BFF3878BF03";
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "EE8FE43F-35E0-4192-91C6-0BFF3878BF03";
PROVISIONING_PROFILE = "";
TARGETED_DEVICE_FAMILY = "1,2";
WRAPPER_EXTENSION = app;
};
Expand All @@ -3350,7 +3364,6 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_WARN_EMPTY_BODY = YES;
CODE_SIGN_IDENTITY = "iPhone Developer: Stefan Gugarel (5V5NEAJJ6M)";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Demo/DTZipArchiveDemo/DTZipArchiveDemo-Prefix.pch";
Expand All @@ -3359,7 +3372,6 @@
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = DTZipArchive;
PROVISIONING_PROFILE = "EE8FE43F-35E0-4192-91C6-0BFF3878BF03";
TARGETED_DEVICE_FAMILY = "1,2";
WRAPPER_EXTENSION = app;
};
Expand Down Expand Up @@ -3555,6 +3567,7 @@
FAF37A3717AFDD93009AC27C /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
Expand Down
31 changes: 27 additions & 4 deletions Demo/DTZipArchiveDemo/Source/ViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ @implementation ViewController
ZipArchiveManager *_zipArchiveManager;
}

- (void)_prepIcons
{
for (ZipArchiveModel *zipArchiveModel in _zipArchiveManager.archives)
{
[self _setupDocumentControllerWithURL:zipArchiveModel.URL];
}
}

- (void)viewDidLoad
{
[super viewDidLoad];
Expand All @@ -42,10 +50,15 @@ - (void)viewDidLoad
NSURL *documentsURL = [NSURL fileURLWithPath:documentsPath];
_zipArchiveManager = [[ZipArchiveManager alloc] initWithURL:documentsURL];

for (ZipArchiveModel *zipArchiveModel in _zipArchiveManager.archives)
{
[self _setupDocumentControllerWithURL:zipArchiveModel.URL];
}
// monitor for changes to the list of archives, e.g. iTunes file sharing
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(archivesDidChange:) name:ZipArchiveManagerDidReloadArchivesNotification object:_zipArchiveManager];

[self _prepIcons];
}

- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)_setupDocumentControllerWithURL:(NSURL *)url
Expand Down Expand Up @@ -150,4 +163,14 @@ - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
}
}

#pragma mark - Notifications
- (void)archivesDidChange:(NSNotification *)notification
{
dispatch_async(dispatch_get_main_queue(), ^{

[self _prepIcons];
[self.tableView reloadData];
});
}

@end
3 changes: 3 additions & 0 deletions Demo/DTZipArchiveDemo/Source/ZipArchiveManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

#import <Foundation/Foundation.h>

// notification that gets sent if the zip archives at the location get reloaded
extern NSString * const ZipArchiveManagerDidReloadArchivesNotification;

@class ZipArchiveModel;

@interface ZipArchiveManager : NSObject
Expand Down
17 changes: 17 additions & 0 deletions Demo/DTZipArchiveDemo/Source/ZipArchiveManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@
#import "ZipArchiveModel.h"
#import "DTZipArchive.h"
#import "NSString+DTPaths.h"
#import "DTFolderMonitor.h"


NSString * const ZipArchiveManagerDidReloadArchivesNotification = @"ZipArchiveManagerDidReloadArchivesNotification";

@implementation ZipArchiveManager
{
NSMutableDictionary *_zipArchivesDictionary;

DTFolderMonitor *_documentsFolderMonitor;
}


Expand All @@ -25,6 +31,17 @@ - (id)initWithURL:(NSURL *)URL
_URL = URL;

[self _setup];

// install a folder monitor
__weak ZipArchiveManager *weakself = self;
_documentsFolderMonitor = [DTFolderMonitor folderMonitorForURL:_URL block:^{

[weakself _setup];

[[NSNotificationCenter defaultCenter] postNotificationName:ZipArchiveManagerDidReloadArchivesNotification object:weakself];
}];

[_documentsFolderMonitor startMonitoring];
}
return self;
}
Expand Down

0 comments on commit 43e9913

Please sign in to comment.