diff --git a/Parse/Internal/Object/PFObjectPrivate.h b/Parse/Internal/Object/PFObjectPrivate.h index 81bcf2edb..8e5ead631 100644 --- a/Parse/Internal/Object/PFObjectPrivate.h +++ b/Parse/Internal/Object/PFObjectPrivate.h @@ -229,7 +229,6 @@ ///-------------------------------------- #pragma mark - Data helpers ///-------------------------------------- -- (void)checkForChangesToMutableContainers; - (void)rebuildEstimatedData; ///-------------------------------------- diff --git a/Parse/Internal/PFInternalUtils.h b/Parse/Internal/PFInternalUtils.h index eedf09e52..f2943c842 100644 --- a/Parse/Internal/PFInternalUtils.h +++ b/Parse/Internal/PFInternalUtils.h @@ -64,13 +64,5 @@ + (NSArray *)arrayBySplittingArray:(NSArray *)array withMaximumComponentsPerSegment:(NSUInteger)components; + (id)_stringWithFormat:(NSString *)format arguments:(NSArray *)arguments; -@end - -@interface PFJSONCacheItem : NSObject - -@property (nonatomic, copy, readonly) NSString *hashValue; - -- (instancetype)initWithObject:(id)object; -+ (PFJSONCacheItem *)cacheFromObject:(id)object; @end diff --git a/Parse/Internal/PFInternalUtils.m b/Parse/Internal/PFInternalUtils.m index 92ccc28bd..f69335213 100644 --- a/Parse/Internal/PFInternalUtils.m +++ b/Parse/Internal/PFInternalUtils.m @@ -269,32 +269,3 @@ + (id)_stringWithFormat:(NSString *)format arguments:(NSArray *)arguments { } @end - -// A PFJSONCacheItem is a pairing of a json string with its hash value. -// This is used by our mutable container checking. -@implementation PFJSONCacheItem - -- (instancetype)initWithObject:(id)object { - self = [super init]; - if (!self) return nil; - - NSObject *encoded = [[PFPointerOrLocalIdObjectEncoder objectEncoder] encodeObject:object]; - NSData *jsonData = [PFJSONSerialization dataFromJSONObject:encoded]; - _hashValue = PFMD5HashFromData(jsonData); - - return self; -} - -- (BOOL)isEqual:(id)otherCache { - if (![otherCache isKindOfClass:[PFJSONCacheItem class]]) { - return NO; - } - - return [self.hashValue isEqualToString:[otherCache hashValue]]; -} - -+ (PFJSONCacheItem *)cacheFromObject:(id)object { - return [[PFJSONCacheItem alloc] initWithObject:object]; -} - -@end diff --git a/Parse/PFObject.m b/Parse/PFObject.m index 6f3361ff4..5b89edbb5 100644 --- a/Parse/PFObject.m +++ b/Parse/PFObject.m @@ -79,25 +79,6 @@ static void PFObjectAssertValueIsKindOfValidClass(id object) { PFParameterAssert(NO, @"PFObject values may not have class: %@", [object class]); } -/*! - Checks if a class is a of container kind to be used as a value for PFObject. - */ -static BOOL PFObjectValueIsKindOfMutableContainerClass(id object) { - static NSArray *classes; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - classes = @[ [NSDictionary class], [NSArray class], [PFACL class], [PFGeoPoint class] ]; - }); - - for (Class class in classes) { - if ([object isKindOfClass:class]) { - return YES; - } - } - - return NO; -} - @interface PFObject () { // A lock for accessing any of the internal state of this object. // Guards basically all of the variables below. @@ -111,9 +92,6 @@ @interface PFObject () { // TODO (grantland): Derive this off the EventuallyPins as opposed to +/- count. NSUInteger _deletingEventuallyCount; - // A dictionary that maps id (objects) => PFJSONCache - NSMutableDictionary *hashedObjectsCache; - NSString *localId; // This queue is used to guarantee the order of *Eventually commands @@ -656,7 +634,6 @@ - (BFTask *)_saveChildrenInBackgroundWithCurrentUser:(PFUser *)currentUser sessi - (BOOL)isDirty:(BOOL)considerChildren { @synchronized (lock) { - [self checkForChangesToMutableContainers]; if (self._state.deleted || dirty || [self _hasChanges]) { return YES; } @@ -683,7 +660,6 @@ - (BOOL)_areChildrenDirty:(NSMutableSet *)seenObjects { [seenObjects addObject:self]; @synchronized(lock) { - [self checkpointAllMutableContainers]; if (self._state.deleted || dirty || [self _hasChanges]) { return YES; } @@ -702,62 +678,6 @@ - (BOOL)_areChildrenDirty:(NSMutableSet *)seenObjects { } } -///-------------------------------------- -#pragma mark - Mutable container management -///-------------------------------------- - -- (void)checkpointAllMutableContainers { - @synchronized (lock) { - [_estimatedData enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) { - [self checkpointMutableContainer:obj]; - }]; - } -} - -- (void)checkpointMutableContainer:(id)object { - @synchronized (lock) { - if (PFObjectValueIsKindOfMutableContainerClass(object)) { - [hashedObjectsCache setObject:[PFJSONCacheItem cacheFromObject:object] - forKey:[NSValue valueWithNonretainedObject:object]]; - } - } -} - -- (void)checkForChangesToMutableContainer:(id)object forKey:(NSString *)key { - @synchronized (lock) { - // If this is a mutable container, we should check its contents. - if (PFObjectValueIsKindOfMutableContainerClass(object)) { - PFJSONCacheItem *oldCacheItem = [hashedObjectsCache objectForKey:[NSValue valueWithNonretainedObject:object]]; - if (!oldCacheItem) { - [NSException raise:NSInternalInconsistencyException - format:@"PFObject contains container item that isn't cached."]; - } else { - PFJSONCacheItem *newCacheItem = [PFJSONCacheItem cacheFromObject:object]; - if (![oldCacheItem isEqual:newCacheItem]) { - // A mutable container changed out from under us. Treat it as a set operation. - [self setObject:object forKey:key]; - } - } - } else { - [hashedObjectsCache removeObjectForKey:[NSValue valueWithNonretainedObject:object]]; - } - } -} - -- (void)checkForChangesToMutableContainers { - @synchronized (lock) { - NSMutableArray *unexaminedCacheKeys = [[hashedObjectsCache allKeys] mutableCopy]; - NSDictionary *reachableData = _estimatedData.dictionaryRepresentation; - [reachableData enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { - [unexaminedCacheKeys removeObject:[NSValue valueWithNonretainedObject:obj]]; - [self checkForChangesToMutableContainer:obj forKey:key]; - }]; - - // Remove unchecked cache entries. - [hashedObjectsCache removeObjectsForKeys:unexaminedCacheKeys]; - } -} - ///-------------------------------------- #pragma mark - Data Availability ///-------------------------------------- @@ -962,7 +882,6 @@ - (NSDictionary *)RESTDictionaryWithObjectEncoder:(PFEncoder *)objectEncoder PFObjectState *state = nil; NSUInteger deletingEventuallyCount = 0; @synchronized (lock) { - [self checkForChangesToMutableContainers]; state = self._state; operationQueue = [[NSArray alloc] initWithArray:operationSetQueue copyItems:YES]; deletingEventuallyCount = _deletingEventuallyCount; @@ -1106,15 +1025,11 @@ - (void)mergeFromRESTDictionary:(NSDictionary *)object withDecoder:(PFDecoder *) if ([key isEqualToString:PFObjectACLRESTKey]) { PFACL *acl = [PFACL ACLWithDictionary:obj]; [state setServerDataObject:acl forKey:PFObjectACLRESTKey]; - [self checkpointMutableContainer:acl]; return; } // Should be decoded id decodedObject = [decoder decodeObject:obj]; - if (PFObjectValueIsKindOfMutableContainerClass(decodedObject)) { - [self checkpointMutableContainer:decodedObject]; - } [state setServerDataObject:decodedObject forKey:key]; }]; if (state.updatedAt == nil && state.createdAt != nil) { @@ -1133,7 +1048,6 @@ - (void)mergeFromRESTDictionary:(NSDictionary *)object withDecoder:(PFDecoder *) } } [self rebuildEstimatedData]; - [self checkpointAllMutableContainers]; } } @@ -1233,8 +1147,6 @@ - (BFTask *)_enqueueSaveEventuallyOperationAsync:(PFOperationSet *)operationSet - (NSMutableDictionary *)_convertToDictionaryForSaving:(PFOperationSet *)changes withObjectEncoder:(PFEncoder *)encoder { @synchronized (lock) { - [self checkForChangesToMutableContainers]; - NSMutableDictionary *serialized = [NSMutableDictionary dictionary]; [changes enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { serialized[key] = obj; @@ -1249,12 +1161,11 @@ - (NSMutableDictionary *)_convertToDictionaryForSaving:(PFOperationSet *)changes */ - (void)performOperation:(PFFieldOperation *)operation forKey:(NSString *)key { @synchronized (lock) { - id newValue = [_estimatedData applyFieldOperation:operation forKey:key]; + [_estimatedData applyFieldOperation:operation forKey:key]; PFFieldOperation *oldOperation = [[self unsavedChanges] objectForKey:key]; PFFieldOperation *newOperation = [operation mergeWithPrevious:oldOperation]; [[self unsavedChanges] setObject:newOperation forKey:key]; - [self checkpointMutableContainer:newValue]; [_availableKeys addObject:key]; } } @@ -1320,7 +1231,6 @@ - (PFObject *)mergeFromObject:(PFObject *)other { state.updatedAt = other.updatedAt; state.serverData = [other._state.serverData mutableCopy]; self._state = state; - [self checkpointAllMutableContainers]; dirty = NO; @@ -1331,13 +1241,11 @@ - (PFObject *)mergeFromObject:(PFObject *)other { - (void)_mergeAfterFetchWithResult:(NSDictionary *)result decoder:(PFDecoder *)decoder completeData:(BOOL)completeData { @synchronized (lock) { - [self checkForChangesToMutableContainers]; [self _mergeFromServerWithResult:result decoder:decoder completeData:completeData]; if (completeData) { [self removeOldKeysAfterFetch:result]; } [self rebuildEstimatedData]; - [self checkpointAllMutableContainers]; } } @@ -1366,16 +1274,12 @@ - (void)_mergeAfterSaveWithResult:(NSDictionary *)result decoder:(PFDecoder *)de PFOperationSet *operationsForNextSave = operationSetQueue[0]; [operationsForNextSave mergeOperationSet:operationsBeforeSave]; } else { - // Merge the data from the save and the data from the server into serverData. - [self checkForChangesToMutableContainers]; - PFMutableObjectState *state = [self._state mutableCopy]; [state applyOperationSet:operationsBeforeSave]; self._state = state; [self _mergeFromServerWithResult:result decoder:decoder completeData:NO]; [self rebuildEstimatedData]; - [self checkpointAllMutableContainers]; } } } @@ -1409,7 +1313,6 @@ - (void)_mergeFromServerWithResult:(NSDictionary *)result decoder:(PFDecoder *)d } else if ([key isEqualToString:PFObjectACLRESTKey]) { PFACL *acl = [PFACL ACLWithDictionary:obj]; [state setServerDataObject:acl forKey:key]; - [self checkpointMutableContainer:acl]; } else { [state setServerDataObject:[decoder decodeObject:obj] forKey:key]; } @@ -1699,7 +1602,6 @@ - (instancetype)init { _estimatedData = [PFObjectEstimatedData estimatedDataFromServerData:_pfinternal_state.serverData operationSetQueue:operationSetQueue]; _availableKeys = [NSMutableSet set]; - hashedObjectsCache = [[NSMutableDictionary alloc] init]; self.taskQueue = [[PFTaskQueue alloc] init]; _eventuallyTaskQueue = [[PFTaskQueue alloc] init]; @@ -2067,7 +1969,6 @@ - (BOOL)isDirty { - (BOOL)isDirtyForKey:(NSString *)key { @synchronized (lock) { - [self checkForChangesToMutableContainer:_estimatedData[key] forKey:key]; return !![[self unsavedChanges] objectForKey:key]; } } @@ -2312,7 +2213,6 @@ - (void)revert { [_availableKeys intersectSet:persistentKeys]; [self rebuildEstimatedData]; - [self checkpointAllMutableContainers]; } } } @@ -2323,7 +2223,6 @@ - (void)revertObjectForKey:(NSString *)key { [[self unsavedChanges] removeObjectForKey:key]; [self rebuildEstimatedData]; [_availableKeys removeObject:key]; - [self checkpointAllMutableContainers]; } } } diff --git a/Parse/PFUser.m b/Parse/PFUser.m index ef0fa6005..59898d9d4 100644 --- a/Parse/PFUser.m +++ b/Parse/PFUser.m @@ -499,14 +499,11 @@ - (BFTask *)signUpAsync:(BFTask *)toAwait { PFConsistencyAssert(!isCurrentUser, @"Attempt to merge currentUser with itself."); - [self checkForChangesToMutableContainers]; @synchronized ([currentUser lock]) { NSString *oldUsername = [currentUser.username copy]; NSString *oldPassword = [currentUser.password copy]; NSArray *oldAnonymousData = currentUser.authData[PFAnonymousUserAuthenticationType]; - [currentUser checkForChangesToMutableContainers]; - // Move the changes to this object over to the currentUser object. PFOperationSet *selfOperations = operationSetQueue[0]; [operationSetQueue removeAllObjects];