PageRenderTime 48ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/Parse/PFInstallation.m

https://gitlab.com/iranjith4/Parse-SDK-iOS-OSX
Objective C | 312 lines | 217 code | 54 blank | 41 comment | 19 complexity | 46ec482b9320cc32a78ebe3c68b7769e MD5 | raw file
  1. /**
  2. * Copyright (c) 2015-present, Parse, LLC.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. */
  9. #import "PFInstallation.h"
  10. #import "PFInstallationPrivate.h"
  11. #import "BFTask+Private.h"
  12. #import "PFApplication.h"
  13. #import "PFAssert.h"
  14. #import "PFCoreManager.h"
  15. #import "PFCurrentInstallationController.h"
  16. #import "PFFileManager.h"
  17. #import "PFInstallationConstants.h"
  18. #import "PFInstallationController.h"
  19. #import "PFInstallationIdentifierStore.h"
  20. #import "PFInternalUtils.h"
  21. #import "PFObject+Subclass.h"
  22. #import "PFObjectEstimatedData.h"
  23. #import "PFObjectPrivate.h"
  24. #import "PFOfflineStore.h"
  25. #import "PFPushPrivate.h"
  26. #import "PFQueryPrivate.h"
  27. #import "Parse_Private.h"
  28. @implementation PFInstallation (Private)
  29. static NSSet *protectedKeys;
  30. + (void)initialize {
  31. static dispatch_once_t onceToken;
  32. dispatch_once(&onceToken, ^{
  33. protectedKeys = PF_SET(PFInstallationKeyDeviceType,
  34. PFInstallationKeyInstallationId,
  35. PFInstallationKeyTimeZone,
  36. PFInstallationKeyParseVersion,
  37. PFInstallationKeyAppVersion,
  38. PFInstallationKeyAppName,
  39. PFInstallationKeyAppIdentifier);
  40. });
  41. }
  42. // Clear device token. Used for testing.
  43. - (void)_clearDeviceToken {
  44. [super removeObjectForKey:PFInstallationKeyDeviceToken];
  45. }
  46. // Check security on delete.
  47. - (void)checkDeleteParams {
  48. PFConsistencyAssert(NO, @"Installations cannot be deleted.");
  49. }
  50. // Validates a class name. We override this to only allow the installation class name.
  51. + (void)_assertValidInstanceClassName:(NSString *)className {
  52. PFParameterAssert([className isEqualToString:[PFInstallation parseClassName]],
  53. @"Cannot initialize a PFInstallation with a custom class name.");
  54. }
  55. - (BOOL)_isCurrentInstallation {
  56. return (self == [[self class] _currentInstallationController].memoryCachedCurrentInstallation);
  57. }
  58. - (void)_markAllFieldsDirty {
  59. @synchronized(self.lock) {
  60. NSDictionary *estimatedData = self._estimatedData.dictionaryRepresentation;
  61. [estimatedData enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
  62. [super setObject:obj forKey:key];
  63. }];
  64. }
  65. }
  66. - (NSString *)displayClassName {
  67. return NSStringFromClass([PFInstallation class]);
  68. }
  69. ///--------------------------------------
  70. #pragma mark - Command Handlers
  71. ///--------------------------------------
  72. - (BFTask *)handleSaveResultAsync:(NSDictionary *)result {
  73. @weakify(self);
  74. return [[super handleSaveResultAsync:result] continueWithBlock:^id(BFTask *task) {
  75. @strongify(self);
  76. BFTask *saveTask = [[[self class] _currentInstallationController] saveCurrentObjectAsync:self];
  77. return [saveTask continueWithResult:task];
  78. }];
  79. }
  80. ///--------------------------------------
  81. #pragma mark - Current Installation Controller
  82. ///--------------------------------------
  83. + (PFCurrentInstallationController *)_currentInstallationController {
  84. return [Parse _currentManager].coreManager.currentInstallationController;
  85. }
  86. @end
  87. @implementation PFInstallation
  88. @dynamic deviceType;
  89. @dynamic installationId;
  90. @dynamic deviceToken;
  91. @dynamic timeZone;
  92. @dynamic channels;
  93. @dynamic badge;
  94. ///--------------------------------------
  95. #pragma mark - PFSubclassing
  96. ///--------------------------------------
  97. + (NSString *)parseClassName {
  98. return @"_Installation";
  99. }
  100. + (PFQuery *)query {
  101. return [super query];
  102. }
  103. ///--------------------------------------
  104. #pragma mark - Current Installation
  105. ///--------------------------------------
  106. + (instancetype)currentInstallation {
  107. BFTask *task = [[self _currentInstallationController] getCurrentObjectAsync];
  108. return [task waitForResult:nil withMainThreadWarning:NO];
  109. }
  110. ///--------------------------------------
  111. #pragma mark - Accessors
  112. ///--------------------------------------
  113. - (id)objectForKey:(NSString *)key {
  114. if ([key isEqualToString:PFInstallationKeyBadge] && [self _isCurrentInstallation]) {
  115. // Update the data dictionary badge value from the device.
  116. [self _updateBadgeFromDevice];
  117. }
  118. return [super objectForKey:key];
  119. }
  120. - (void)setObject:(id)object forKey:(NSString *)key {
  121. PFParameterAssert(![protectedKeys containsObject:key],
  122. @"Can't change the '%@' field of a PFInstallation.", key);
  123. if ([key isEqualToString:PFInstallationKeyBadge]) {
  124. // Set the application badge and update the badge value in the data dictionary.
  125. NSInteger badge = [object integerValue];
  126. PFParameterAssert(badge >= 0, @"Can't set the badge to less than zero.");
  127. [PFApplication currentApplication].iconBadgeNumber = badge;
  128. [super setObject:@(badge) forKey:PFInstallationKeyBadge];
  129. }
  130. [super setObject:object forKey:key];
  131. }
  132. - (void)incrementKey:(NSString *)key byAmount:(NSNumber *)amount {
  133. PFParameterAssert(![key isEqualToString:PFInstallationKeyBadge],
  134. @"Can't atomically increment the 'badge' field of a PFInstallation.");
  135. [super incrementKey:key byAmount:amount];
  136. }
  137. - (void)removeObjectForKey:(NSString *)key {
  138. PFParameterAssert(![protectedKeys containsObject:key],
  139. @"Can't remove the '%@' field of a PFInstallation.", key);
  140. PFParameterAssert(![key isEqualToString:PFInstallationKeyBadge],
  141. @"Can't remove the 'badge' field of a PFInstallation.");
  142. [super removeObjectForKey:key];
  143. }
  144. // Internal mutators override the dynamic accessor and use super to avoid
  145. // read-only checks on automatic fields.
  146. - (void)setDeviceType:(NSString *)deviceType {
  147. [self _setObject:deviceType forKey:PFInstallationKeyDeviceType onlyIfDifferent:YES];
  148. }
  149. - (void)setInstallationId:(NSString *)installationId {
  150. [self _setObject:installationId forKey:PFInstallationKeyInstallationId onlyIfDifferent:YES];
  151. }
  152. - (void)setDeviceToken:(NSString *)deviceToken {
  153. [self _setObject:deviceToken forKey:PFInstallationKeyDeviceToken onlyIfDifferent:YES];
  154. }
  155. - (void)setDeviceTokenFromData:(NSData *)deviceTokenData {
  156. [self _setObject:[[PFPush pushInternalUtilClass] convertDeviceTokenToString:deviceTokenData]
  157. forKey:PFInstallationKeyDeviceToken
  158. onlyIfDifferent:YES];
  159. }
  160. - (void)setTimeZone:(NSString *)timeZone {
  161. [self _setObject:timeZone forKey:PFInstallationKeyTimeZone onlyIfDifferent:YES];
  162. }
  163. - (void)setChannels:(NSArray *)channels {
  164. [self _setObject:channels forKey:PFInstallationKeyChannels onlyIfDifferent:YES];
  165. }
  166. ///--------------------------------------
  167. #pragma mark - PFObject
  168. ///--------------------------------------
  169. - (BFTask *)saveInBackground {
  170. [self _updateAutomaticInfo];
  171. return [super saveInBackground];
  172. }
  173. - (BFTask *)_enqueueSaveEventuallyWithChildren:(BOOL)saveChildren {
  174. [self _updateAutomaticInfo];
  175. return [super _enqueueSaveEventuallyWithChildren:saveChildren];
  176. }
  177. - (BFTask *)saveEventually {
  178. [self _updateAutomaticInfo];
  179. return [super saveEventually];
  180. }
  181. - (BFTask *)saveAsync:(BFTask *)toAwait {
  182. return [[super saveAsync:toAwait] continueWithBlock:^id(BFTask *task) {
  183. // Do not attempt to resave an object if LDS is enabled, since changing objectId is not allowed.
  184. if ([Parse _currentManager].offlineStoreLoaded) {
  185. return task;
  186. }
  187. if (task.error.code == kPFErrorObjectNotFound) {
  188. @synchronized (self.lock) {
  189. // Retry the fetch as a save operation because this Installation was deleted on the server.
  190. // We always want [currentInstallation save] to succeed.
  191. self.objectId = nil;
  192. [self _markAllFieldsDirty];
  193. return [super saveAsync:nil];
  194. }
  195. }
  196. return task;
  197. }];
  198. }
  199. - (BOOL)needsDefaultACL {
  200. return NO;
  201. }
  202. ///--------------------------------------
  203. #pragma mark - Automatic Info
  204. ///--------------------------------------
  205. - (void)_updateAutomaticInfo {
  206. if ([self _isCurrentInstallation]) {
  207. @synchronized(self.lock) {
  208. [self _updateTimeZoneFromDevice];
  209. [self _updateBadgeFromDevice];
  210. [self _updateVersionInfoFromDevice];
  211. }
  212. }
  213. }
  214. - (void)_updateTimeZoneFromDevice {
  215. // Get the system time zone (after clearing the cached value) and update
  216. // the installation if necessary.
  217. NSString *systemTimeZoneName = [PFInternalUtils currentSystemTimeZoneName];
  218. if (![systemTimeZoneName isEqualToString:self.timeZone]) {
  219. self.timeZone = systemTimeZoneName;
  220. }
  221. }
  222. - (void)_updateBadgeFromDevice {
  223. // Get the application icon and update the installation if necessary.
  224. NSNumber *applicationBadge = @([PFApplication currentApplication].iconBadgeNumber);
  225. NSNumber *installationBadge = [super objectForKey:PFInstallationKeyBadge];
  226. if (installationBadge == nil || ![applicationBadge isEqualToNumber:installationBadge]) {
  227. [super setObject:applicationBadge forKey:PFInstallationKeyBadge];
  228. }
  229. }
  230. - (void)_updateVersionInfoFromDevice {
  231. NSDictionary *appInfo = [[NSBundle mainBundle] infoDictionary];
  232. NSString *appName = appInfo[(__bridge NSString *)kCFBundleNameKey];
  233. NSString *appVersion = appInfo[(__bridge NSString *)kCFBundleVersionKey];
  234. NSString *appIdentifier = appInfo[(__bridge NSString *)kCFBundleIdentifierKey];
  235. // It's possible that the app was created without an info.plist and we just
  236. // cannot get the data we need.
  237. // Note: it's important to make the possibly nil string the message receptor for
  238. // nil propegation instead of a BAD_ACCESS
  239. if (appName && ![self[PFInstallationKeyAppName] isEqualToString:appName]) {
  240. [super setObject:appName forKey:PFInstallationKeyAppName];
  241. }
  242. if (appVersion && ![self[PFInstallationKeyAppVersion] isEqualToString:appVersion]) {
  243. [super setObject:appVersion forKey:PFInstallationKeyAppVersion];
  244. }
  245. if (appIdentifier && ![self[PFInstallationKeyAppIdentifier] isEqualToString:appIdentifier]) {
  246. [super setObject:appIdentifier forKey:PFInstallationKeyAppIdentifier];
  247. }
  248. if (![self[PFInstallationKeyParseVersion] isEqualToString:PARSE_VERSION]) {
  249. [super setObject:PARSE_VERSION forKey:PFInstallationKeyParseVersion];
  250. }
  251. }
  252. ///--------------------------------------
  253. #pragma mark - Data Source
  254. ///--------------------------------------
  255. + (id<PFObjectControlling>)objectController {
  256. return [Parse _currentManager].coreManager.installationController;
  257. }
  258. @end