This repository is currently being migrated. It's locked while the migration is in progress.
-
Notifications
You must be signed in to change notification settings - Fork 91
Expand file tree
/
Copy pathGVUserDefaults.m
More file actions
292 lines (239 loc) · 8.83 KB
/
GVUserDefaults.m
File metadata and controls
292 lines (239 loc) · 8.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
//
// GVUserDefaults.m
// GVUserDefaults
//
// Created by Kevin Renskers on 18-12-12.
// Copyright (c) 2012 Gangverk. All rights reserved.
//
#import "GVUserDefaults.h"
#import <objc/runtime.h>
@interface GVUserDefaults ()
@property (strong, nonatomic) NSMutableDictionary *mapping;
@property (strong, nonatomic) NSUserDefaults *userDefaults;
@end
@implementation GVUserDefaults
enum TypeEncodings {
Char = 'c',
Bool = 'B',
Short = 's',
Int = 'i',
Long = 'l',
LongLong = 'q',
UnsignedChar = 'C',
UnsignedShort = 'S',
UnsignedInt = 'I',
UnsignedLong = 'L',
UnsignedLongLong = 'Q',
Float = 'f',
Double = 'd',
Object = '@'
};
- (NSUserDefaults *)userDefaults {
if (!_userDefaults) {
NSString *suiteName = nil;
if ([NSUserDefaults instancesRespondToSelector:@selector(initWithSuiteName:)]) {
suiteName = [self _suiteName];
}
if (suiteName && suiteName.length) {
_userDefaults = [[NSUserDefaults alloc] initWithSuiteName:suiteName];
} else {
_userDefaults = [NSUserDefaults standardUserDefaults];
}
}
return _userDefaults;
}
- (NSString *)defaultsKeyForPropertyNamed:(char const *)propertyName {
NSString *key = [NSString stringWithFormat:@"%s", propertyName];
return [self _transformKey:key];
}
- (NSString *)defaultsKeyForSelector:(SEL)selector {
return [self.mapping objectForKey:NSStringFromSelector(selector)];
}
static long long longLongGetter(GVUserDefaults *self, SEL _cmd) {
NSString *key = [self defaultsKeyForSelector:_cmd];
return [[self.userDefaults objectForKey:key] longLongValue];
}
static void longLongSetter(GVUserDefaults *self, SEL _cmd, long long value) {
NSString *key = [self defaultsKeyForSelector:_cmd];
NSNumber *object = [NSNumber numberWithLongLong:value];
[self.userDefaults setObject:object forKey:key];
}
static bool boolGetter(GVUserDefaults *self, SEL _cmd) {
NSString *key = [self defaultsKeyForSelector:_cmd];
return [self.userDefaults boolForKey:key];
}
static void boolSetter(GVUserDefaults *self, SEL _cmd, bool value) {
NSString *key = [self defaultsKeyForSelector:_cmd];
[self.userDefaults setBool:value forKey:key];
}
static int integerGetter(GVUserDefaults *self, SEL _cmd) {
NSString *key = [self defaultsKeyForSelector:_cmd];
return (int)[self.userDefaults integerForKey:key];
}
static void integerSetter(GVUserDefaults *self, SEL _cmd, int value) {
NSString *key = [self defaultsKeyForSelector:_cmd];
[self.userDefaults setInteger:value forKey:key];
}
static float floatGetter(GVUserDefaults *self, SEL _cmd) {
NSString *key = [self defaultsKeyForSelector:_cmd];
return [self.userDefaults floatForKey:key];
}
static void floatSetter(GVUserDefaults *self, SEL _cmd, float value) {
NSString *key = [self defaultsKeyForSelector:_cmd];
[self.userDefaults setFloat:value forKey:key];
}
static double doubleGetter(GVUserDefaults *self, SEL _cmd) {
NSString *key = [self defaultsKeyForSelector:_cmd];
return [self.userDefaults doubleForKey:key];
}
static void doubleSetter(GVUserDefaults *self, SEL _cmd, double value) {
NSString *key = [self defaultsKeyForSelector:_cmd];
[self.userDefaults setDouble:value forKey:key];
}
static id objectGetter(GVUserDefaults *self, SEL _cmd) {
NSString *key = [self defaultsKeyForSelector:_cmd];
return [self.userDefaults objectForKey:key];
}
static void objectSetter(GVUserDefaults *self, SEL _cmd, id object) {
NSString *key = [self defaultsKeyForSelector:_cmd];
if (object) {
[self.userDefaults setObject:object forKey:key];
} else {
[self.userDefaults removeObjectForKey:key];
}
}
#pragma mark - Begin
+ (instancetype)standardUserDefaults {
static dispatch_once_t pred;
static GVUserDefaults *sharedInstance = nil;
dispatch_once(&pred, ^{ sharedInstance = [[self alloc] init]; });
return sharedInstance;
}
+ (BOOL)ignoreSynthesizedProperties {
return NO;
}
+ (NSArray<NSString *> *)ignoredKeys {
return nil;
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wundeclared-selector"
#pragma GCC diagnostic ignored "-Warc-performSelector-leaks"
- (instancetype)init {
self = [super init];
if (self) {
SEL setupDefaultSEL = NSSelectorFromString([NSString stringWithFormat:@"%@pDefaults", @"setu"]);
if ([self respondsToSelector:setupDefaultSEL]) {
NSDictionary *defaults = [self performSelector:setupDefaultSEL];
NSMutableDictionary *mutableDefaults = [NSMutableDictionary dictionaryWithCapacity:[defaults count]];
for (NSString *key in defaults) {
id value = [defaults objectForKey:key];
NSString *transformedKey = [self _transformKey:key];
[mutableDefaults setObject:value forKey:transformedKey];
}
[self.userDefaults registerDefaults:mutableDefaults];
}
[self generateAccessorMethods];
}
return self;
}
- (NSString *)_transformKey:(NSString *)key {
if ([self respondsToSelector:@selector(transformKey:)]) {
return [self performSelector:@selector(transformKey:) withObject:key];
}
return key;
}
- (NSString *)_suiteName {
// Backwards compatibility (v 1.0.0)
if ([self respondsToSelector:@selector(suitName)]) {
return [self performSelector:@selector(suitName)];
}
if ([self respondsToSelector:@selector(suiteName)]) {
return [self performSelector:@selector(suiteName)];
}
return nil;
}
#pragma GCC diagnostic pop
- (void)generateAccessorMethods {
unsigned int count = 0;
objc_property_t *properties = class_copyPropertyList([self class], &count);
self.mapping = [NSMutableDictionary dictionary];
for (int i = 0; i < count; ++i) {
objc_property_t property = properties[i];
const char *name = property_getName(property);
const char *attributes = property_getAttributes(property);
if ((void *)(strstr(attributes, ",D")-attributes) == NULL
|| ([self.class ignoredKeys] != nil
&& [[self.class ignoredKeys] containsObject:[[NSString alloc] initWithUTF8String:name]])) {
continue;
}
char *getter = strstr(attributes, ",G");
if (getter) {
getter = strdup(getter + 2);
getter = strsep(&getter, ",");
} else {
getter = strdup(name);
}
SEL getterSel = sel_registerName(getter);
free(getter);
char *setter = strstr(attributes, ",S");
if (setter) {
setter = strdup(setter + 2);
setter = strsep(&setter, ",");
} else {
asprintf(&setter, "set%c%s:", toupper(name[0]), name + 1);
}
SEL setterSel = sel_registerName(setter);
free(setter);
NSString *key = [self defaultsKeyForPropertyNamed:name];
[self.mapping setValue:key forKey:NSStringFromSelector(getterSel)];
[self.mapping setValue:key forKey:NSStringFromSelector(setterSel)];
IMP getterImp = NULL;
IMP setterImp = NULL;
char type = attributes[1];
switch (type) {
case Short:
case Long:
case LongLong:
case UnsignedChar:
case UnsignedShort:
case UnsignedInt:
case UnsignedLong:
case UnsignedLongLong:
getterImp = (IMP)longLongGetter;
setterImp = (IMP)longLongSetter;
break;
case Bool:
case Char:
getterImp = (IMP)boolGetter;
setterImp = (IMP)boolSetter;
break;
case Int:
getterImp = (IMP)integerGetter;
setterImp = (IMP)integerSetter;
break;
case Float:
getterImp = (IMP)floatGetter;
setterImp = (IMP)floatSetter;
break;
case Double:
getterImp = (IMP)doubleGetter;
setterImp = (IMP)doubleSetter;
break;
case Object:
getterImp = (IMP)objectGetter;
setterImp = (IMP)objectSetter;
break;
default:
free(properties);
[NSException raise:NSInternalInconsistencyException format:@"Unsupported type of property \"%s\" in class %@", name, self];
break;
}
char types[5];
snprintf(types, 4, "%c@:", type);
class_addMethod([self class], getterSel, getterImp, types);
snprintf(types, 5, "v@:%c", type);
class_addMethod([self class], setterSel, setterImp, types);
}
free(properties);
}
@end