Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// Copyright 2018 Google
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
 
15
#import "GoogleUtilities/UserDefaults/Public/GoogleUtilities/GULUserDefaults.h"
16
 
17
#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h"
18
 
19
NS_ASSUME_NONNULL_BEGIN
20
 
21
static NSTimeInterval const kGULSynchronizeInterval = 1.0;
22
 
23
static NSString *const kGULLogFormat = @"I-GUL%06ld";
24
 
25
static GULLoggerService kGULLogUserDefaultsService = @"[GoogleUtilities/UserDefaults]";
26
 
27
typedef NS_ENUM(NSInteger, GULUDMessageCode) {
28
  GULUDMessageCodeInvalidKeyGet = 1,
29
  GULUDMessageCodeInvalidKeySet = 2,
30
  GULUDMessageCodeInvalidObjectSet = 3,
31
  GULUDMessageCodeSynchronizeFailed = 4,
32
};
33
 
34
@interface GULUserDefaults ()
35
 
36
/// Equivalent to the suite name for NSUserDefaults.
37
@property(readonly) CFStringRef appNameRef;
38
 
39
@property(atomic) BOOL isPreferenceFileExcluded;
40
 
41
@end
42
 
43
@implementation GULUserDefaults {
44
  // The application name is the same with the suite name of the NSUserDefaults, and it is used for
45
  // preferences.
46
  CFStringRef _appNameRef;
47
}
48
 
49
+ (GULUserDefaults *)standardUserDefaults {
50
  static GULUserDefaults *standardUserDefaults;
51
  static dispatch_once_t onceToken;
52
  dispatch_once(&onceToken, ^{
53
    standardUserDefaults = [[GULUserDefaults alloc] init];
54
  });
55
  return standardUserDefaults;
56
}
57
 
58
- (instancetype)init {
59
  return [self initWithSuiteName:nil];
60
}
61
 
62
- (instancetype)initWithSuiteName:(nullable NSString *)suiteName {
63
  self = [super init];
64
 
65
  NSString *name = [suiteName copy];
66
 
67
  if (self) {
68
    // `kCFPreferencesCurrentApplication` maps to the same defaults database as
69
    // `[NSUserDefaults standardUserDefaults]`.
70
    _appNameRef =
71
        name.length ? (__bridge_retained CFStringRef)name : kCFPreferencesCurrentApplication;
72
  }
73
 
74
  return self;
75
}
76
 
77
- (void)dealloc {
78
  // If we're using a custom `_appNameRef` it needs to be released. If it's a constant, it shouldn't
79
  // need to be released since we don't own it.
80
  if (CFStringCompare(_appNameRef, kCFPreferencesCurrentApplication, 0) != kCFCompareEqualTo) {
81
    CFRelease(_appNameRef);
82
  }
83
 
84
  [NSObject cancelPreviousPerformRequestsWithTarget:self
85
                                           selector:@selector(synchronize)
86
                                             object:nil];
87
}
88
 
89
- (nullable id)objectForKey:(NSString *)defaultName {
90
  NSString *key = [defaultName copy];
91
  if (![key isKindOfClass:[NSString class]] || !key.length) {
92
    GULLogWarning(@"<GoogleUtilities>", NO,
93
                  [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeInvalidKeyGet],
94
                  @"Cannot get object for invalid user default key.");
95
    return nil;
96
  }
97
  return (__bridge_transfer id)CFPreferencesCopyAppValue((__bridge CFStringRef)key, _appNameRef);
98
}
99
 
100
- (void)setObject:(nullable id)value forKey:(NSString *)defaultName {
101
  NSString *key = [defaultName copy];
102
  if (![key isKindOfClass:[NSString class]] || !key.length) {
103
    GULLogWarning(kGULLogUserDefaultsService, NO,
104
                  [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeInvalidKeySet],
105
                  @"Cannot set object for invalid user default key.");
106
    return;
107
  }
108
  if (!value) {
109
    CFPreferencesSetAppValue((__bridge CFStringRef)key, NULL, _appNameRef);
110
    [self scheduleSynchronize];
111
    return;
112
  }
113
  BOOL isAcceptableValue =
114
      [value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNumber class]] ||
115
      [value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]] ||
116
      [value isKindOfClass:[NSDate class]] || [value isKindOfClass:[NSData class]];
117
  if (!isAcceptableValue) {
118
    GULLogWarning(kGULLogUserDefaultsService, NO,
119
                  [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeInvalidObjectSet],
120
                  @"Cannot set invalid object to user defaults. Must be a string, number, array, "
121
                  @"dictionary, date, or data. Value: %@",
122
                  value);
123
    return;
124
  }
125
 
126
  CFPreferencesSetAppValue((__bridge CFStringRef)key, (__bridge CFStringRef)value, _appNameRef);
127
  [self scheduleSynchronize];
128
}
129
 
130
- (void)removeObjectForKey:(NSString *)key {
131
  [self setObject:nil forKey:key];
132
}
133
 
134
#pragma mark - Getters
135
 
136
- (NSInteger)integerForKey:(NSString *)defaultName {
137
  NSNumber *object = [self objectForKey:defaultName];
138
  return object.integerValue;
139
}
140
 
141
- (float)floatForKey:(NSString *)defaultName {
142
  NSNumber *object = [self objectForKey:defaultName];
143
  return object.floatValue;
144
}
145
 
146
- (double)doubleForKey:(NSString *)defaultName {
147
  NSNumber *object = [self objectForKey:defaultName];
148
  return object.doubleValue;
149
}
150
 
151
- (BOOL)boolForKey:(NSString *)defaultName {
152
  NSNumber *object = [self objectForKey:defaultName];
153
  return object.boolValue;
154
}
155
 
156
- (nullable NSString *)stringForKey:(NSString *)defaultName {
157
  return [self objectForKey:defaultName];
158
}
159
 
160
- (nullable NSArray *)arrayForKey:(NSString *)defaultName {
161
  return [self objectForKey:defaultName];
162
}
163
 
164
- (nullable NSDictionary<NSString *, id> *)dictionaryForKey:(NSString *)defaultName {
165
  return [self objectForKey:defaultName];
166
}
167
 
168
#pragma mark - Setters
169
 
170
- (void)setInteger:(NSInteger)integer forKey:(NSString *)defaultName {
171
  [self setObject:@(integer) forKey:defaultName];
172
}
173
 
174
- (void)setFloat:(float)value forKey:(NSString *)defaultName {
175
  [self setObject:@(value) forKey:defaultName];
176
}
177
 
178
- (void)setDouble:(double)doubleNumber forKey:(NSString *)defaultName {
179
  [self setObject:@(doubleNumber) forKey:defaultName];
180
}
181
 
182
- (void)setBool:(BOOL)boolValue forKey:(NSString *)defaultName {
183
  [self setObject:@(boolValue) forKey:defaultName];
184
}
185
 
186
#pragma mark - Save data
187
 
188
- (void)synchronize {
189
  if (!CFPreferencesAppSynchronize(_appNameRef)) {
190
    GULLogError(kGULLogUserDefaultsService, NO,
191
                [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeSynchronizeFailed],
192
                @"Cannot synchronize user defaults to disk");
193
  }
194
}
195
 
196
#pragma mark - Private methods
197
 
198
- (void)scheduleSynchronize {
199
  // Synchronize data using a timer so that multiple set... calls can be coalesced under one
200
  // synchronize.
201
  [NSObject cancelPreviousPerformRequestsWithTarget:self
202
                                           selector:@selector(synchronize)
203
                                             object:nil];
204
  // This method may be called on multiple queues (due to set... methods can be called on any queue)
205
  // synchronize can be scheduled on different queues, so make sure that it does not crash. If this
206
  // instance goes away, self will be released also, no one will retain it and the schedule won't be
207
  // called.
208
  [self performSelector:@selector(synchronize) withObject:nil afterDelay:kGULSynchronizeInterval];
209
}
210
 
211
@end
212
 
213
NS_ASSUME_NONNULL_END