Skip to content

Commit 197863b

Browse files
committed
More info on change notifications
1 parent 7ae0060 commit 197863b

3 files changed

Lines changed: 51 additions & 12 deletions

File tree

FCModel/FCModel.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,23 @@ extern NSString * const FCModelInstanceKey;
3535
// "Changed" field names may be overly inclusive: all named fields may not *actually* have changed, but all actual changes will be in the set.
3636
//
3737
extern NSString * const FCModelChangedFieldsKey;
38+
//
39+
// userInfo[FCModelOldFieldValuesKey] is an NSDictionary of NSString field names to values.
40+
// Only included in update notifications.
41+
// If included, it may be overly inclusive: all specified fields may not *actually* have changed, but all actual changes will be present.
42+
//
43+
extern NSString * const FCModelOldFieldValuesKey;
44+
//
45+
// userInfo[FCModelChangeTypeKey] is an NSNumber from the following enum:
46+
//
47+
extern NSString * const FCModelChangeTypeKey;
48+
49+
typedef NS_ENUM(NSInteger, FCModelChangeType) {
50+
FCModelChangeTypeUnspecified, // Any change or changes may have been made
51+
FCModelChangeTypeInsert, // The object in FCModelInstanceKey is non-nil, and was inserted into the database
52+
FCModelChangeTypeUpdate, // The object in FCModelInstanceKey is non-nil, and was updated in the database
53+
FCModelChangeTypeDelete // The object in FCModelInstanceKey is non-nil, and was deleted from the database
54+
};
3855

3956

4057
@interface FCModel : NSObject

FCModel/FCModel.m

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
NSString * const FCModelChangeNotification = @"FCModelChangeNotification";
2121
NSString * const FCModelInstanceKey = @"FCModelInstanceKey";
2222
NSString * const FCModelChangedFieldsKey = @"FCModelChangedFieldsKey";
23-
23+
NSString * const FCModelChangeTypeKey = @"FCModelChangeTypeKey";
24+
NSString * const FCModelOldFieldValuesKey = @"FCModelOldFieldValuesKey";
2425
NSString * const FCModelWillSendChangeNotification = @"FCModelWillSendChangeNotification"; // for FCModelCachedObject
2526

2627
static NSMutableDictionary *g_instances = NULL;
@@ -41,7 +42,7 @@ @interface FCModel () {
4142
FCModelInDatabaseStatus _inDatabaseStatus;
4243
}
4344
@property (nonatomic, copy) NSDictionary *_rowValuesInDatabase;
44-
+ (void)postChangeNotificationWithChangedFields:(NSSet *)changedFields;
45+
+ (void)postChangeNotificationWithChangedFields:(NSSet *)changedFields changedObject:(FCModel *)changedObject changeType:(FCModelChangeType)changeType priorFieldValues:(NSDictionary *)priorFieldValues;
4546
@end
4647

4748
static inline BOOL checkForOpenDatabaseFatal(BOOL fatal)
@@ -575,6 +576,8 @@ - (BOOL)_save
575576

576577
__block BOOL hadChanges = NO;
577578
__block NSSet *changedFields;
579+
__block FCModelChangeType changeType = FCModelChangeTypeUnspecified;
580+
__block NSDictionary *previousRowValuesInDatabase = nil;
578581
fcm_onMainThread(^{
579582
[g_database inDatabase:^(FMDatabase *db) {
580583

@@ -594,11 +597,13 @@ - (BOOL)_save
594597
if (update) {
595598
columnNames = [changes allKeys];
596599
changedFields = [NSSet setWithArray:columnNames];
600+
changeType = FCModelChangeTypeUpdate;
597601
} else {
598602
changedFields = [NSSet setWithArray:self.class.databaseFieldNames];
599603
NSMutableSet *columnNamesMinusPK = [[NSSet setWithArray:[g_fieldInfo[self.class] allKeys]] mutableCopy];
600604
[columnNamesMinusPK removeObject:pkName];
601605
columnNames = [columnNamesMinusPK allObjects];
606+
changeType = FCModelChangeTypeInsert;
602607
}
603608

604609
// Validate NOT NULL columns
@@ -649,8 +654,8 @@ - (BOOL)_save
649654
g_database.isInInternalWrite = NO;
650655
if (! success) [self.class queryFailedInDatabase:db];
651656

652-
NSDictionary *rowValuesInDatabase = self._rowValuesInDatabase;
653-
NSMutableDictionary *newRowValues = rowValuesInDatabase ? [rowValuesInDatabase mutableCopy] : [NSMutableDictionary dictionary];
657+
previousRowValuesInDatabase = self._rowValuesInDatabase;
658+
NSMutableDictionary *newRowValues = previousRowValuesInDatabase ? [previousRowValuesInDatabase mutableCopy] : [NSMutableDictionary dictionary];
654659
[changes enumerateKeysAndObjectsUsingBlock:^(NSString *fieldName, id obj, BOOL *stop) {
655660
newRowValues[fieldName] = obj ?: NSNull.null;
656661
}];
@@ -660,7 +665,7 @@ - (BOOL)_save
660665
hadChanges = YES;
661666
}];
662667

663-
if (hadChanges) [self.class postChangeNotificationWithChangedFields:changedFields];
668+
if (hadChanges) [self.class postChangeNotificationWithChangedFields:changedFields changedObject:self changeType:changeType priorFieldValues:previousRowValuesInDatabase];
664669
});
665670
return hadChanges;
666671
}
@@ -687,7 +692,7 @@ - (void)delete
687692

688693
[g_instances[self.class] removeObjectForKey:pkValue];
689694

690-
[self.class postChangeNotificationWithChangedFields:nil];
695+
[self.class postChangeNotificationWithChangedFields:nil changedObject:self changeType:FCModelChangeTypeDelete priorFieldValues:nil];
691696
});
692697
}
693698

@@ -1006,7 +1011,7 @@ + (BOOL)vacuumIfPossible
10061011
return success;
10071012
}
10081013

1009-
+ (void)postChangeNotificationWithChangedFields:(NSSet *)changedFields
1014+
+ (void)postChangeNotificationWithChangedFields:(NSSet *)changedFields changedObject:(FCModel *)changedObject changeType:(FCModelChangeType)changeType priorFieldValues:(NSDictionary *)priorFieldValues
10101015
{
10111016
if (! changedFields) changedFields = [NSSet setWithArray:self.class.databaseFieldNames];
10121017

@@ -1017,7 +1022,24 @@ + (void)postChangeNotificationWithChangedFields:(NSSet *)changedFields
10171022
else g_database.enqueuedChangedFieldsByClass[class] = [changedFields mutableCopy];
10181023
} else {
10191024
// notify immediately
1020-
NSDictionary *userInfo = @{ FCModelChangedFieldsKey : changedFields };
1025+
NSDictionary *userInfo =
1026+
changedObject ? (
1027+
changeType == FCModelChangeTypeUpdate && priorFieldValues ?
1028+
@{
1029+
FCModelChangedFieldsKey : changedFields,
1030+
FCModelChangeTypeKey : @(changeType),
1031+
FCModelInstanceKey : changedObject,
1032+
FCModelOldFieldValuesKey : priorFieldValues,
1033+
} : @{
1034+
FCModelChangedFieldsKey : changedFields,
1035+
FCModelChangeTypeKey : @(changeType),
1036+
FCModelInstanceKey : changedObject,
1037+
}
1038+
) : @{
1039+
FCModelChangedFieldsKey : changedFields,
1040+
FCModelChangeTypeKey : @(FCModelChangeTypeUnspecified)
1041+
}
1042+
;
10211043
[NSNotificationCenter.defaultCenter postNotificationName:FCModelWillSendChangeNotification object:self userInfo:userInfo];
10221044
[NSNotificationCenter.defaultCenter postNotificationName:FCModelChangeNotification object:self userInfo:userInfo];
10231045
}
@@ -1032,7 +1054,7 @@ + (void)dataChangedExternally
10321054
for (FCModel *m in classCache.objectEnumerator.allObjects) [m reload];
10331055
}
10341056

1035-
[modelClass postChangeNotificationWithChangedFields:nil];
1057+
[modelClass postChangeNotificationWithChangedFields:nil changedObject:nil changeType:FCModelChangeTypeUnspecified priorFieldValues:nil];
10361058
}];
10371059
});
10381060
}

FCModel/FCModelDatabase.m

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#import <sqlite3.h>
1111

1212
@interface FCModel ()
13-
+ (void)postChangeNotificationWithChangedFields:(NSSet *)changedFields;
13+
+ (void)postChangeNotificationWithChangedFields:(NSSet *)changedFields changedObject:(FCModel *)changedObject changeType:(FCModelChangeType)changeType priorFieldValues:(NSDictionary *)priorFieldValues;
1414
+ (void)dataChangedExternally;
1515
@end
1616

@@ -37,8 +37,8 @@ static void _sqlite3_update_hook(void *context, int sqlite_operation, char const
3737

3838
// Can't run synchronously since SQLite requires that no other database queries are executed before this function returns,
3939
// and queries are likely to be executed by any notification listeners.
40-
if (queue.isQueuingNotifications) [class postChangeNotificationWithChangedFields:nil];
41-
else dispatch_async(dispatch_get_main_queue(), ^{ [class postChangeNotificationWithChangedFields:nil]; });
40+
if (queue.isQueuingNotifications) [class postChangeNotificationWithChangedFields:nil changedObject:nil changeType:FCModelChangeTypeUnspecified priorFieldValues:nil];
41+
else dispatch_async(dispatch_get_main_queue(), ^{ [class postChangeNotificationWithChangedFields:nil changedObject:nil changeType:FCModelChangeTypeUnspecified priorFieldValues:nil]; });
4242
}
4343

4444
@interface FCModelDatabase () {

0 commit comments

Comments
 (0)