Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
/*
2
 * Copyright 2019 Google
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
 
17
#import "FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.h"
18
#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
19
#import "FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h"
20
 
21
static NSString *const kRCNGroupPrefix = @"group";
22
static NSString *const kRCNGroupSuffix = @"firebase";
23
static NSString *const kRCNUserDefaultsKeyNamelastETag = @"lastETag";
24
static NSString *const kRCNUserDefaultsKeyNamelastETagUpdateTime = @"lastETagUpdateTime";
25
static NSString *const kRCNUserDefaultsKeyNameLastSuccessfulFetchTime = @"lastSuccessfulFetchTime";
26
static NSString *const kRCNUserDefaultsKeyNamelastFetchStatus = @"lastFetchStatus";
27
static NSString *const kRCNUserDefaultsKeyNameIsClientThrottled =
28
    @"isClientThrottledWithExponentialBackoff";
29
static NSString *const kRCNUserDefaultsKeyNameThrottleEndTime = @"throttleEndTime";
30
static NSString *const kRCNUserDefaultsKeyNamecurrentThrottlingRetryInterval =
31
    @"currentThrottlingRetryInterval";
32
 
33
@interface RCNUserDefaultsManager () {
34
  /// User Defaults instance for this bundleID. NSUserDefaults is guaranteed to be thread-safe.
35
  NSUserDefaults *_userDefaults;
36
  /// The suite name for this user defaults instance. It is a combination of a prefix and the
37
  /// bundleID. This is because you cannot use just the bundleID of the current app as the suite
38
  /// name when initializing user defaults.
39
  NSString *_userDefaultsSuiteName;
40
  /// The FIRApp that this instance is scoped within.
41
  NSString *_firebaseAppName;
42
  /// The Firebase Namespace that this instance is scoped within.
43
  NSString *_firebaseNamespace;
44
  /// The bundleID of the app. In case of an extension, this will be the bundleID of the parent app.
45
  NSString *_bundleIdentifier;
46
}
47
 
48
@end
49
 
50
@implementation RCNUserDefaultsManager
51
 
52
#pragma mark Initializers.
53
 
54
/// Designated initializer.
55
- (instancetype)initWithAppName:(NSString *)appName
56
                       bundleID:(NSString *)bundleIdentifier
57
                      namespace:(NSString *)firebaseNamespace {
58
  self = [super init];
59
  if (self) {
60
    _firebaseAppName = appName;
61
    _bundleIdentifier = bundleIdentifier;
62
    NSInteger location = [firebaseNamespace rangeOfString:@":"].location;
63
    if (location == NSNotFound) {
64
      FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000064",
65
                  @"Error: Namespace %@ is not fully qualified app:namespace.", firebaseNamespace);
66
      _firebaseNamespace = firebaseNamespace;
67
    } else {
68
      _firebaseNamespace = [firebaseNamespace substringToIndex:location];
69
    }
70
 
71
    // Initialize the user defaults with a prefix and the bundleID. For app extensions, this will be
72
    // the bundleID of the app extension.
73
    _userDefaults =
74
        [RCNUserDefaultsManager sharedUserDefaultsForBundleIdentifier:_bundleIdentifier];
75
  }
76
 
77
  return self;
78
}
79
 
80
+ (NSUserDefaults *)sharedUserDefaultsForBundleIdentifier:(NSString *)bundleIdentifier {
81
  static dispatch_once_t onceToken;
82
  static NSUserDefaults *sharedInstance;
83
  dispatch_once(&onceToken, ^{
84
    NSString *userDefaultsSuiteName =
85
        [RCNUserDefaultsManager userDefaultsSuiteNameForBundleIdentifier:bundleIdentifier];
86
    sharedInstance = [[NSUserDefaults alloc] initWithSuiteName:userDefaultsSuiteName];
87
  });
88
  return sharedInstance;
89
}
90
 
91
+ (NSString *)userDefaultsSuiteNameForBundleIdentifier:(NSString *)bundleIdentifier {
92
  NSString *suiteName =
93
      [NSString stringWithFormat:@"%@.%@.%@", kRCNGroupPrefix, bundleIdentifier, kRCNGroupSuffix];
94
  return suiteName;
95
}
96
 
97
#pragma mark Public properties.
98
 
99
- (NSString *)lastETag {
100
  return [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNamelastETag];
101
}
102
 
103
- (void)setLastETag:(NSString *)lastETag {
104
  if (lastETag) {
105
    [self setInstanceUserDefaultsValue:lastETag forKey:kRCNUserDefaultsKeyNamelastETag];
106
  }
107
}
108
 
109
- (NSTimeInterval)lastETagUpdateTime {
110
  NSNumber *lastETagUpdateTime =
111
      [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNamelastETagUpdateTime];
112
  return lastETagUpdateTime.doubleValue;
113
}
114
 
115
- (void)setLastETagUpdateTime:(NSTimeInterval)lastETagUpdateTime {
116
  if (lastETagUpdateTime) {
117
    [self setInstanceUserDefaultsValue:@(lastETagUpdateTime)
118
                                forKey:kRCNUserDefaultsKeyNamelastETagUpdateTime];
119
  }
120
}
121
 
122
- (NSTimeInterval)lastFetchTime {
123
  NSNumber *lastFetchTime =
124
      [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNameLastSuccessfulFetchTime];
125
  return lastFetchTime.doubleValue;
126
}
127
 
128
- (void)setLastFetchTime:(NSTimeInterval)lastFetchTime {
129
  [self setInstanceUserDefaultsValue:@(lastFetchTime)
130
                              forKey:kRCNUserDefaultsKeyNameLastSuccessfulFetchTime];
131
}
132
 
133
- (NSString *)lastFetchStatus {
134
  return [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNamelastFetchStatus];
135
}
136
 
137
- (void)setLastFetchStatus:(NSString *)lastFetchStatus {
138
  if (lastFetchStatus) {
139
    [self setInstanceUserDefaultsValue:lastFetchStatus
140
                                forKey:kRCNUserDefaultsKeyNamelastFetchStatus];
141
  }
142
}
143
 
144
- (BOOL)isClientThrottledWithExponentialBackoff {
145
  NSNumber *isClientThrottled =
146
      [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNameIsClientThrottled];
147
  return isClientThrottled.boolValue;
148
}
149
 
150
- (void)setIsClientThrottledWithExponentialBackoff:(BOOL)isClientThrottled {
151
  [self setInstanceUserDefaultsValue:@(isClientThrottled)
152
                              forKey:kRCNUserDefaultsKeyNameIsClientThrottled];
153
}
154
 
155
- (NSTimeInterval)throttleEndTime {
156
  NSNumber *throttleEndTime =
157
      [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNameThrottleEndTime];
158
  return throttleEndTime.doubleValue;
159
}
160
 
161
- (void)setThrottleEndTime:(NSTimeInterval)throttleEndTime {
162
  [self setInstanceUserDefaultsValue:@(throttleEndTime)
163
                              forKey:kRCNUserDefaultsKeyNameThrottleEndTime];
164
}
165
 
166
- (NSTimeInterval)currentThrottlingRetryIntervalSeconds {
167
  NSNumber *throttleEndTime = [[self instanceUserDefaults]
168
      objectForKey:kRCNUserDefaultsKeyNamecurrentThrottlingRetryInterval];
169
  return throttleEndTime.doubleValue;
170
}
171
 
172
- (void)setCurrentThrottlingRetryIntervalSeconds:(NSTimeInterval)throttlingRetryIntervalSeconds {
173
  [self setInstanceUserDefaultsValue:@(throttlingRetryIntervalSeconds)
174
                              forKey:kRCNUserDefaultsKeyNamecurrentThrottlingRetryInterval];
175
}
176
 
177
#pragma mark Public methods.
178
- (void)resetUserDefaults {
179
  [self resetInstanceUserDefaults];
180
}
181
 
182
#pragma mark Private methods.
183
 
184
// There is a nested hierarchy for the userdefaults as follows:
185
// [FIRAppName][FIRNamespaceName][Key]
186
- (nonnull NSDictionary *)appUserDefaults {
187
  NSString *appPath = _firebaseAppName;
188
  NSDictionary *appDict = [_userDefaults valueForKeyPath:appPath];
189
  if (!appDict) {
190
    appDict = [[NSDictionary alloc] init];
191
  }
192
  return appDict;
193
}
194
 
195
// Search for the user defaults for this (app, namespace) instance using the valueForKeyPath method.
196
- (nonnull NSDictionary *)instanceUserDefaults {
197
  NSString *appNamespacePath =
198
      [NSString stringWithFormat:@"%@.%@", _firebaseAppName, _firebaseNamespace];
199
  NSDictionary *appNamespaceDict = [_userDefaults valueForKeyPath:appNamespacePath];
200
 
201
  if (!appNamespaceDict) {
202
    appNamespaceDict = [[NSMutableDictionary alloc] init];
203
  }
204
  return appNamespaceDict;
205
}
206
 
207
// Update users defaults for just this (app, namespace) instance.
208
- (void)setInstanceUserDefaultsValue:(NSObject *)value forKey:(NSString *)key {
209
  @synchronized(_userDefaults) {
210
    NSMutableDictionary *appUserDefaults = [[self appUserDefaults] mutableCopy];
211
    NSMutableDictionary *appNamespaceUserDefaults = [[self instanceUserDefaults] mutableCopy];
212
    [appNamespaceUserDefaults setObject:value forKey:key];
213
    [appUserDefaults setObject:appNamespaceUserDefaults forKey:_firebaseNamespace];
214
    [_userDefaults setObject:appUserDefaults forKey:_firebaseAppName];
215
    // We need to synchronize to have this value updated for the extension.
216
    [_userDefaults synchronize];
217
  }
218
}
219
 
220
// Delete any existing userdefaults for this instance.
221
- (void)resetInstanceUserDefaults {
222
  @synchronized(_userDefaults) {
223
    NSMutableDictionary *appUserDefaults = [[self appUserDefaults] mutableCopy];
224
    NSMutableDictionary *appNamespaceUserDefaults = [[self instanceUserDefaults] mutableCopy];
225
    [appNamespaceUserDefaults removeAllObjects];
226
    [appUserDefaults setObject:appNamespaceUserDefaults forKey:_firebaseNamespace];
227
    [_userDefaults setObject:appUserDefaults forKey:_firebaseAppName];
228
    // We need to synchronize to have this value updated for the extension.
229
    [_userDefaults synchronize];
230
  }
231
}
232
 
233
@end