diff --git a/YapDatabase/YapDatabase.h b/YapDatabase/YapDatabase.h index df6de5b4e..6a308ae2f 100644 --- a/YapDatabase/YapDatabase.h +++ b/YapDatabase/YapDatabase.h @@ -97,6 +97,44 @@ typedef id __nonnull (^YapDatabaseDeserializer)(NSString *collection, NSString * typedef id __nonnull (^YapDatabasePreSanitizer)(NSString *collection, NSString *key, id obj); typedef void (^YapDatabasePostSanitizer)(NSString *collection, NSString *key, id obj); +/** + * This notification is posted when a YapDatabase instance is deallocated, + * and has thus closed all references to the underlying sqlite files. + * + * If you intend to delete the sqlite file(s) from disk, + * it's recommended you use this notification as a hook to do so. + * + * More info: + * The YapDatabase class itself is just a retainer for the filepath, blocks, config, etc. + * And YapDatabaseConnection(s) open a sqlite connection to the database file, + * and rely on the blocks & config in the parent YapDatabase class. + * Thus a YapDatabaseConnection instance purposely retains the YapDatabase instance. + * This means that in order to fully close all references to the underlying sqlite file(s), + * you need to deallocate YapDatabase and all associated YapDatabaseConnections. + * While this may be simple in concept, it's generally difficult to know exactly when all + * the instances have been deallocated. Especially when there may be a bunch of asynchronous operations going. + * + * Therefore the best approach is to do the following: + * - destroy your YapDatabase instance (set it to nil) + * - destroy all YapDatabaseConnection instances + * - wait for YapDatabaseClosedNotification + * - use notification as hook to delete all associated sqlite files from disk + * + * The userInfo dictionary will look like this: + * @{ + * YapDatabasePathKey : , + * YapDatabasePathWalKey : , + * YapDatabasePathShmKey : , + * } + * + * This notification is always posted to the main thread. +**/ +extern NSString *const YapDatabaseClosedNotification; + +extern NSString *const YapDatabasePathKey; +extern NSString *const YapDatabasePathWalKey; +extern NSString *const YapDatabasePathShmKey; + /** * This notification is posted following a readwrite transaction where the database was modified. * @@ -108,10 +146,10 @@ typedef void (^YapDatabasePostSanitizer)(NSString *collection, NSString *key, id * * The userInfo dictionary will look something like this: * @{ - * YapDatabaseSnapshotKey = , - * YapDatabaseConnectionKey = , - * YapDatabaseExtensionsKey = , - * YapDatabaseCustomKey = , + * YapDatabaseSnapshotKey : , + * YapDatabaseConnectionKey : , + * YapDatabaseExtensionsKey : , + * YapDatabaseCustomKey : , * } * * This notification is always posted to the main thread. diff --git a/YapDatabase/YapDatabase.m b/YapDatabase/YapDatabase.m index a45bef2e3..66fe30f46 100644 --- a/YapDatabase/YapDatabase.m +++ b/YapDatabase/YapDatabase.m @@ -28,6 +28,12 @@ static const int ydbLogLevel = YDB_LOG_LEVEL_WARN; #endif +NSString *const YapDatabaseClosedNotification = @"YapDatabaseClosedNotification"; + +NSString *const YapDatabasePathKey = @"databasePath"; +NSString *const YapDatabasePathWalKey = @"databasePath_wal"; +NSString *const YapDatabasePathShmKey = @"databasePath_shm"; + NSString *const YapDatabaseModifiedNotification = @"YapDatabaseModifiedNotification"; NSString *const YapDatabaseSnapshotKey = @"snapshot"; @@ -549,6 +555,16 @@ - (void)dealloc { YDBLogVerbose(@"Dealloc <%@ %p: databaseName=%@>", [self class], self, [databasePath lastPathComponent]); + NSDictionary *userInfo = @{ + YapDatabasePathKey : self.databasePath ?: @"", + YapDatabasePathWalKey : self.databasePath_wal ?: @"", + YapDatabasePathShmKey : self.databasePath_shm ?: @"" + }; + NSNotification *notification = + [NSNotification notificationWithName:YapDatabaseClosedNotification + object:nil // Cannot retain self within dealloc method + userInfo:userInfo]; + while ([connectionPoolValues count] > 0) { sqlite3 *aDb = (sqlite3 *)[[connectionPoolValues objectAtIndex:0] pointerValue]; @@ -583,6 +599,11 @@ - (void)dealloc if (checkpointQueue) dispatch_release(checkpointQueue); #endif + + dispatch_async(dispatch_get_main_queue(), ^{ + + [[NSNotificationCenter defaultCenter] postNotification:notification]; + }); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////