diff --git a/Parse.xcodeproj/project.pbxproj b/Parse.xcodeproj/project.pbxproj index d8df3f0a9..d8684a59b 100644 --- a/Parse.xcodeproj/project.pbxproj +++ b/Parse.xcodeproj/project.pbxproj @@ -8597,6 +8597,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 81DCD1491D2DA080002501A2 /* Debug.xcconfig */; buildSettings = { + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -8604,6 +8605,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 81DCD14A1D2DA080002501A2 /* Release.xcconfig */; buildSettings = { + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/Parse/Internal/ACL/State/PFACLState.h b/Parse/Internal/ACL/State/PFACLState.h index d0c6c439b..4a1d30761 100644 --- a/Parse/Internal/ACL/State/PFACLState.h +++ b/Parse/Internal/ACL/State/PFACLState.h @@ -17,7 +17,7 @@ typedef void (^PFACLStateMutationBlock)(PFMutableACLState *); @interface PFACLState : PFBaseState -@property (nonatomic, copy, readonly) NSDictionary *permissions; +@property (nonatomic, strong, readonly) NSDictionary *permissions; @property (nonatomic, assign, readonly, getter=isShared) BOOL shared; ///-------------------------------------- diff --git a/Parse/Internal/ACL/State/PFACLState_Private.h b/Parse/Internal/ACL/State/PFACLState_Private.h index bab64a182..e2906f410 100644 --- a/Parse/Internal/ACL/State/PFACLState_Private.h +++ b/Parse/Internal/ACL/State/PFACLState_Private.h @@ -26,7 +26,7 @@ BOOL _shared; } -@property (nonatomic, copy, readwrite) NSDictionary *permissions; +@property (nonatomic, strong, readwrite) NSDictionary *permissions; @property (nonatomic, assign, readwrite, getter=isShared) BOOL shared; @end diff --git a/Parse/Internal/ACL/State/PFMutableACLState.h b/Parse/Internal/ACL/State/PFMutableACLState.h index f0a1a1c41..229e1465c 100644 --- a/Parse/Internal/ACL/State/PFMutableACLState.h +++ b/Parse/Internal/ACL/State/PFMutableACLState.h @@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN @interface PFMutableACLState : PFACLState -@property (nonatomic, copy, readwrite) NSMutableDictionary *permissions; +@property (nonatomic, strong, readwrite) NSMutableDictionary *permissions; @property (nonatomic, assign, readwrite, getter=isShared) BOOL shared; @end diff --git a/Parse/Internal/KeyValueCache/PFKeyValueCache.h b/Parse/Internal/KeyValueCache/PFKeyValueCache.h index 5faef2bc9..7768d13f9 100644 --- a/Parse/Internal/KeyValueCache/PFKeyValueCache.h +++ b/Parse/Internal/KeyValueCache/PFKeyValueCache.h @@ -35,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - Getting ///-------------------------------------- -- (NSString *)objectForKey:(NSString *)key maxAge:(NSTimeInterval)age; +- (nullable NSString *)objectForKey:(NSString *)key maxAge:(NSTimeInterval)age; ///-------------------------------------- #pragma mark - Removing diff --git a/Parse/Internal/KeyValueCache/PFKeyValueCache.m b/Parse/Internal/KeyValueCache/PFKeyValueCache.m index 77c755ebd..b75cd6492 100644 --- a/Parse/Internal/KeyValueCache/PFKeyValueCache.m +++ b/Parse/Internal/KeyValueCache/PFKeyValueCache.m @@ -127,7 +127,7 @@ - (void)setObject:(NSString *)value forKey:(NSString *)key { }); } -- (NSString *)objectForKey:(NSString *)key maxAge:(NSTimeInterval)maxAge { +- (nullable NSString *)objectForKey:(NSString *)key maxAge:(NSTimeInterval)maxAge { NSURL *cacheURL = [self _cacheURLForKey:key]; PFKeyValueCacheEntry *cacheEntry = [self.memoryCache objectForKey:key]; diff --git a/Parse/Internal/LocalDataStore/OfflineQueryLogic/PFOfflineQueryLogic.m b/Parse/Internal/LocalDataStore/OfflineQueryLogic/PFOfflineQueryLogic.m index 3ff4530d0..9eddc757c 100644 --- a/Parse/Internal/LocalDataStore/OfflineQueryLogic/PFOfflineQueryLogic.m +++ b/Parse/Internal/LocalDataStore/OfflineQueryLogic/PFOfflineQueryLogic.m @@ -145,7 +145,7 @@ - (id)valueForContainer:(id)container } else if ([key isEqualToString:@"updatedAt"] || [key isEqualToString:@"_updated_at"]) { return object.updatedAt; } else { - return object[key]; + return key ? object[key] : nil; } } else if ([container isKindOfClass:[NSDictionary class]]) { return ((NSDictionary *)container)[key]; diff --git a/Parse/Internal/Object/PFObjectPrivate.h b/Parse/Internal/Object/PFObjectPrivate.h index 5ce305ff2..fb8714e76 100644 --- a/Parse/Internal/Object/PFObjectPrivate.h +++ b/Parse/Internal/Object/PFObjectPrivate.h @@ -85,7 +85,7 @@ @return Current object state. */ @property (nonatomic, copy) PFObjectState *_state; -@property (nonatomic, copy) NSMutableSet *_availableKeys; +@property (nonatomic, strong) NSMutableSet *_availableKeys; - (instancetype)initWithObjectState:(PFObjectState *)state; + (instancetype)objectWithClassName:(NSString *)className diff --git a/Parse/Internal/Object/Subclassing/PFObjectSubclassingController.m b/Parse/Internal/Object/Subclassing/PFObjectSubclassingController.m index 1be108765..e5c8e1a36 100644 --- a/Parse/Internal/Object/Subclassing/PFObjectSubclassingController.m +++ b/Parse/Internal/Object/Subclassing/PFObjectSubclassingController.m @@ -343,7 +343,12 @@ - (void)_registerSubclassesInLoadedBundle:(NSBundle *)bundle { } - (void)_registerSubclassesInBundle:(NSBundle *)bundle { - PFConsistencyAssert(bundle.loaded, @"Cannot register subclasses in an unloaded bundle: %@", bundle); + // Prevent crash by loading the bundle if it's not loaded yet (see: https://github.com/ParsePlatform/Parse-SDK-iOS-OSX/issues/1006 ): + NSError *error = nil; + if (!bundle.loaded) { + [bundle loadAndReturnError:&error]; + } + PFConsistencyAssert(bundle.loaded, @"Cannot register subclasses in a bundle that hasn't been loaded!"); const char *executablePath = bundle.executablePath.UTF8String; if (executablePath == NULL) { diff --git a/Parse/Internal/Object/Utilities/PFObjectUtilities.h b/Parse/Internal/Object/Utilities/PFObjectUtilities.h index f4b225141..8044d1dab 100644 --- a/Parse/Internal/Object/Utilities/PFObjectUtilities.h +++ b/Parse/Internal/Object/Utilities/PFObjectUtilities.h @@ -20,7 +20,7 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - Operations ///-------------------------------------- -+ (id)newValueByApplyingFieldOperation:(PFFieldOperation *)operation ++ (nullable id)newValueByApplyingFieldOperation:(PFFieldOperation *)operation toDictionary:(NSMutableDictionary *)dictionary forKey:(NSString *)key; + (void)applyOperationSet:(PFOperationSet *)operationSet toDictionary:(NSMutableDictionary *)dictionary; diff --git a/Parse/Internal/Object/Utilities/PFObjectUtilities.m b/Parse/Internal/Object/Utilities/PFObjectUtilities.m index 9b5f1e12b..58e5fb80e 100644 --- a/Parse/Internal/Object/Utilities/PFObjectUtilities.m +++ b/Parse/Internal/Object/Utilities/PFObjectUtilities.m @@ -18,7 +18,7 @@ @implementation PFObjectUtilities #pragma mark - Operations ///-------------------------------------- -+ (id)newValueByApplyingFieldOperation:(PFFieldOperation *)operation ++ (nullable id)newValueByApplyingFieldOperation:(PFFieldOperation *)operation toDictionary:(NSMutableDictionary *)dictionary forKey:(NSString *)key { id oldValue = dictionary[key]; diff --git a/Parse/Internal/PFDateFormatter.h b/Parse/Internal/PFDateFormatter.h index 3fb91092b..ff92b55be 100644 --- a/Parse/Internal/PFDateFormatter.h +++ b/Parse/Internal/PFDateFormatter.h @@ -26,7 +26,7 @@ NS_ASSUME_NONNULL_BEGIN @return Formatted `NSString` representation. */ -- (NSString *)preciseStringFromDate:(NSDate *)date; +- (nullable NSString *)preciseStringFromDate:(NSDate *)date; ///-------------------------------------- #pragma mark - Date from String diff --git a/Parse/Internal/PFDateFormatter.m b/Parse/Internal/PFDateFormatter.m index 1f8707929..78d47ea53 100644 --- a/Parse/Internal/PFDateFormatter.m +++ b/Parse/Internal/PFDateFormatter.m @@ -69,7 +69,7 @@ - (void)dealloc { #pragma mark - String from Date ///-------------------------------------- -- (NSString *)preciseStringFromDate:(NSDate *)date { +- (nullable NSString *)preciseStringFromDate:(NSDate *)date { __block NSString *string = nil; NSTimeInterval interval = date.timeIntervalSince1970; dispatch_sync(_synchronizationQueue, ^{ diff --git a/Parse/Internal/PFEventuallyQueue.m b/Parse/Internal/PFEventuallyQueue.m index 663024e7b..0de7782da 100644 --- a/Parse/Internal/PFEventuallyQueue.m +++ b/Parse/Internal/PFEventuallyQueue.m @@ -73,7 +73,9 @@ - (instancetype)initWithDataSource:(id)dataSource _commandEnqueueTaskQueue = [[PFTaskQueue alloc] init]; _taskCompletionSources = [NSMutableDictionary dictionary]; - _testHelper = [[PFEventuallyQueueTestHelper alloc] init]; + + // we don't want your leaky test helper +// _testHelper = [[PFEventuallyQueueTestHelper alloc] init]; [self _startMonitoringNetworkReachability]; diff --git a/Parse/Internal/PropertyInfo/PFPropertyInfo.m b/Parse/Internal/PropertyInfo/PFPropertyInfo.m index d3c856e95..f875dd606 100644 --- a/Parse/Internal/PropertyInfo/PFPropertyInfo.m +++ b/Parse/Internal/PropertyInfo/PFPropertyInfo.m @@ -58,7 +58,7 @@ - (instancetype)initWithClass:(Class)kls name:(NSString *)propertyName _ivar = class_getInstanceVariable(kls, safeStringWithPropertyAttributeValue(objcProperty, "V").UTF8String); if (_ivar) break; - // Walk the superclass heirarchy for the property definition. Because property attributes are not inherited + // Walk the superclass hierarchy for the property definition. Because property attributes are not inherited // (but property definitions *are*), we must be careful to ensure that the variable was never actually // implemented and synthesized in a superclass. Note if the same property is synthesized in multiple classes // with different iVars, we take the class furthest from the root class as the 'source of truth'. @@ -94,7 +94,9 @@ - (instancetype)initWithClass:(Class)kls name:(NSString *)propertyName propertySetter = [NSString stringWithFormat:@"set%@:", stringByCapitalizingFirstCharacter(_name)]; } - _setterSelector = NSSelectorFromString(propertySetter); + if (propertySetter != nil) { + _setterSelector = NSSelectorFromString(propertySetter); + } if (_associationType == PFPropertyInfoAssociationTypeDefault) { BOOL isCopy = safeStringWithPropertyAttributeValue(objcProperty, "C") != nil; diff --git a/Parse/Internal/Query/Controller/PFQueryController.h b/Parse/Internal/Query/Controller/PFQueryController.h index adf809457..16637df04 100644 --- a/Parse/Internal/Query/Controller/PFQueryController.h +++ b/Parse/Internal/Query/Controller/PFQueryController.h @@ -78,7 +78,7 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - Caching ///-------------------------------------- -- (NSString *)cacheKeyForQueryState:(PFQueryState *)queryState sessionToken:(nullable NSString *)sessionToken; +- (nullable NSString *)cacheKeyForQueryState:(PFQueryState *)queryState sessionToken:(nullable NSString *)sessionToken; - (BOOL)hasCachedResultForQueryState:(PFQueryState *)queryState sessionToken:(nullable NSString *)sessionToken; - (void)clearCachedResultForQueryState:(PFQueryState *)queryState sessionToken:(nullable NSString *)sessionToken; diff --git a/Parse/Internal/Query/Controller/PFQueryController.m b/Parse/Internal/Query/Controller/PFQueryController.m index 9058ab305..667ac7583 100644 --- a/Parse/Internal/Query/Controller/PFQueryController.m +++ b/Parse/Internal/Query/Controller/PFQueryController.m @@ -127,7 +127,7 @@ - (BFTask *)countObjectsAsyncForQueryState:(PFQueryState *)queryState #pragma mark - Caching ///-------------------------------------- -- (NSString *)cacheKeyForQueryState:(PFQueryState *)queryState sessionToken:(NSString *)sessionToken { +- (nullable NSString *)cacheKeyForQueryState:(PFQueryState *)queryState sessionToken:(NSString *)sessionToken { return nil; } diff --git a/Parse/Internal/Relation/State/PFMutableRelationState.h b/Parse/Internal/Relation/State/PFMutableRelationState.h index 3fd99eddb..67174ad02 100644 --- a/Parse/Internal/Relation/State/PFMutableRelationState.h +++ b/Parse/Internal/Relation/State/PFMutableRelationState.h @@ -13,7 +13,7 @@ @property (nonatomic, weak, readwrite) PFObject *parent; @property (nonatomic, copy, readwrite) NSString *targetClass; -@property (nonatomic, copy, readwrite) NSMutableSet *knownObjects; +@property (nonatomic, strong, readwrite) NSMutableSet *knownObjects; @property (nonatomic, copy, readwrite) NSString *key; @end diff --git a/Parse/Internal/Relation/State/PFRelationState.h b/Parse/Internal/Relation/State/PFRelationState.h index 3ce8e80c0..48ad19642 100644 --- a/Parse/Internal/Relation/State/PFRelationState.h +++ b/Parse/Internal/Relation/State/PFRelationState.h @@ -17,7 +17,7 @@ @property (nonatomic, copy, readonly) NSString *parentClassName; @property (nonatomic, copy, readonly) NSString *parentObjectId; @property (nonatomic, copy, readonly) NSString *targetClass; -@property (nonatomic, copy, readonly) NSSet *knownObjects; +@property (nonatomic, strong, readonly) NSSet *knownObjects; @property (nonatomic, copy, readonly) NSString *key; ///-------------------------------------- diff --git a/Parse/Internal/Relation/State/PFRelationState_Private.h b/Parse/Internal/Relation/State/PFRelationState_Private.h index f8c841537..47efdd9ff 100644 --- a/Parse/Internal/Relation/State/PFRelationState_Private.h +++ b/Parse/Internal/Relation/State/PFRelationState_Private.h @@ -33,7 +33,7 @@ @property (nonatomic, copy, readwrite) NSString *parentClassName; @property (nonatomic, copy, readwrite) NSString *parentObjectId; @property (nonatomic, copy, readwrite) NSString *targetClass; -@property (nonatomic, copy, readwrite) NSSet *knownObjects; +@property (nonatomic, strong, readwrite) NSSet *knownObjects; @property (nonatomic, copy, readwrite) NSString *key; @end diff --git a/Parse/PFObject.m b/Parse/PFObject.m index 21848f6c3..77ea51d27 100644 --- a/Parse/PFObject.m +++ b/Parse/PFObject.m @@ -776,7 +776,9 @@ + (id)_objectFromDictionary:(NSDictionary *)dictionary defaultClassName:defaultClassName completeData:(selectedKeys == nil) decoder:[PFDecoder objectDecoder]]; - [result->_availableKeys addObjectsFromArray:selectedKeys]; + if (selectedKeys) { + [result->_availableKeys addObjectsFromArray:selectedKeys]; + } return result; } @@ -789,7 +791,7 @@ + (id)_objectFromDictionary:(NSDictionary *)dictionary @param decoder Decoder used to decode the dictionary. */ + (id)_objectFromDictionary:(NSDictionary *)dictionary - defaultClassName:(NSString *)defaultClassName + defaultClassName:(nonnull NSString *)defaultClassName completeData:(BOOL)completeData decoder:(PFDecoder *)decoder { NSString *objectId = nil; @@ -798,7 +800,8 @@ + (id)_objectFromDictionary:(NSDictionary *)dictionary objectId = dictionary[@"objectId"]; className = dictionary[@"className"] ?: defaultClassName; } - PFObject *object = [PFObject objectWithoutDataWithClassName:className objectId:objectId]; + // Temp fix for nil className possibility: + PFObject *object = [PFObject objectWithoutDataWithClassName:className ?: @"" objectId:objectId]; [object _mergeAfterFetchWithResult:dictionary decoder:decoder completeData:completeData]; return object; } @@ -964,7 +967,7 @@ - (void)mergeFromRESTDictionary:(NSDictionary *)object withDecoder:(PFDecoder *) } PFOperationSet *localOperationSet = [self unsavedChanges]; - if (localOperationSet.updatedAt != nil && + if (localOperationSet.updatedAt != nil && remoteOperationSet.updatedAt != nil && [localOperationSet.updatedAt compare:remoteOperationSet.updatedAt] != NSOrderedAscending) { [localOperationSet mergeOperationSet:remoteOperationSet]; } else { @@ -1304,7 +1307,9 @@ - (void)_mergeFromServerWithResult:(NSDictionary *)result decoder:(PFDecoder *)d state.updatedAt = state.createdAt; } }]; - [_availableKeys addObjectsFromArray:result.allKeys]; + if (result.allKeys) { + [_availableKeys addObjectsFromArray:result.allKeys]; + } dirty = NO; } diff --git a/Tests/Other/Swift/SwiftSubclass.swift b/Tests/Other/Swift/SwiftSubclass.swift index 6db82970c..c83e5489e 100644 --- a/Tests/Other/Swift/SwiftSubclass.swift +++ b/Tests/Other/Swift/SwiftSubclass.swift @@ -16,7 +16,7 @@ public class SwiftSubclass: PFObject, PFSubclassing { @NSManaged public var primitiveProperty: Int @NSManaged public var objectProperty: AnyObject? - @NSManaged public var relationProperty: PFRelation? + @NSManaged public var relationProperty: PFRelation? @NSManaged public var badProperty: CGPoint public static func parseClassName() -> String { diff --git a/Tests/Unit/ObjectSubclassingControllerTests.m b/Tests/Unit/ObjectSubclassingControllerTests.m index 9e4306251..5cd692383 100644 --- a/Tests/Unit/ObjectSubclassingControllerTests.m +++ b/Tests/Unit/ObjectSubclassingControllerTests.m @@ -373,7 +373,7 @@ - (void)testSwiftGetters { [subclassingController forwardObjectInvocation:invocation withObject:target]; __unsafe_unretained PFRelation *returnValue = nil; [invocation getReturnValue:&returnValue]; - XCTAssertTrue([returnValue isKindOfClass:[PFRelation class]]); + XCTAssertTrue([returnValue isKindOfClass:[PFRelation class]], @"return value was %@", [returnValue class] ? NSStringFromClass([returnValue class]) : @"nil"); invocation = [self _forwardingInvocationForTarget:target selector:@selector(badProperty)