提交
This commit is contained in:
15
Pods/GVUserDefaults/GVUserDefaults/GVUserDefaults.h
generated
Executable file
15
Pods/GVUserDefaults/GVUserDefaults/GVUserDefaults.h
generated
Executable file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// GVUserDefaults.h
|
||||
// GVUserDefaults
|
||||
//
|
||||
// Created by Kevin Renskers on 18-12-12.
|
||||
// Copyright (c) 2012 Gangverk. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface GVUserDefaults : NSObject
|
||||
|
||||
+ (instancetype)standardUserDefaults;
|
||||
|
||||
@end
|
||||
279
Pods/GVUserDefaults/GVUserDefaults/GVUserDefaults.m
generated
Executable file
279
Pods/GVUserDefaults/GVUserDefaults/GVUserDefaults.m
generated
Executable file
@@ -0,0 +1,279 @@
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
|
||||
#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);
|
||||
|
||||
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
|
||||
19
Pods/GVUserDefaults/LICENSE
generated
Executable file
19
Pods/GVUserDefaults/LICENSE
generated
Executable file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2012 Gangverk ehf. http://gangverk.is
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
99
Pods/GVUserDefaults/README.md
generated
Executable file
99
Pods/GVUserDefaults/README.md
generated
Executable file
@@ -0,0 +1,99 @@
|
||||
# GVUserDefaults - NSUserDefaults access via properties
|
||||
|
||||
[](http://cocoadocs.org/docsets/GVUserDefaults)
|
||||
[](http://cocoadocs.org/docsets/GVUserDefaults)
|
||||
|
||||
Tired of writing all that code to get and set defaults in NSUserDefaults? Want to have code completion and compiler checks by using properties instead?
|
||||
|
||||
## Usage
|
||||
Create a category on `GVUserDefaults`, add some properties in the .h file and make them `@dynamic` in the .m file.
|
||||
|
||||
// .h
|
||||
@interface GVUserDefaults (Properties)
|
||||
@property (nonatomic, weak) NSString *userName;
|
||||
@property (nonatomic, weak) NSNumber *userId;
|
||||
@property (nonatomic) NSInteger integerValue;
|
||||
@property (nonatomic) BOOL boolValue;
|
||||
@property (nonatomic) float floatValue;
|
||||
@end
|
||||
|
||||
// .m
|
||||
@implementation GVUserDefaults (Properties)
|
||||
@dynamic userName;
|
||||
@dynamic userId;
|
||||
@dynamic integerValue;
|
||||
@dynamic boolValue;
|
||||
@dynamic floatValue;
|
||||
@end
|
||||
|
||||
Now, instead of using `[[NSUserDefaults standardUserDefaults] objectForKey:@"userName"]`, you can simply use `[GVUserDefaults standardUserDefaults].userName`.
|
||||
|
||||
You can even save defaults by setting the property:
|
||||
|
||||
[GVUserDefaults standardUserDefaults].userName = @"myusername";
|
||||
|
||||
|
||||
### Key prefix
|
||||
The keys in NSUserDefaults are the same name as your properties. If you'd like to prefix or alter them, add a `transformKey:` method to your category. For example, to turn "userName" into "NSUserDefaultUserName":
|
||||
|
||||
- (NSString *)transformKey:(NSString *)key {
|
||||
key = [key stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[key substringToIndex:1] uppercaseString]];
|
||||
return [NSString stringWithFormat:@"NSUserDefault%@", key];
|
||||
}
|
||||
|
||||
### Registering defaults
|
||||
Registering defaults can be done as usual, on NSUserDefaults directly (use the same prefix, if any!).
|
||||
|
||||
NSDictionary *defaults = @{
|
||||
@"NSUserDefaultUserName": @"default",
|
||||
@"NSUserDefaultUserId": @1,
|
||||
@"NSUserDefaultBoolValue": @YES
|
||||
};
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
|
||||
|
||||
However, it's a lot easier to create a setupDefaults method on the category, which takes care of the transformed keys automatically:
|
||||
|
||||
- (NSDictionary *)setupDefaults {
|
||||
return @{
|
||||
@"userName": @"default",
|
||||
@"userId": @1,
|
||||
@"boolValue": @YES
|
||||
};
|
||||
}
|
||||
|
||||
### NSUserDefaults initWithSuitName support
|
||||
Simply create a methods called `suitName` in your category and return the suitName you wish to use:
|
||||
|
||||
- (NSString *)suitName {
|
||||
return @"com.example.mySuitName";
|
||||
}
|
||||
|
||||
|
||||
### Performance
|
||||
Performance is nearly identical to using NSUserDefaults directly. We're talking about a difference of 0.05 milliseconds or less.
|
||||
|
||||
|
||||
## Install
|
||||
Install via [CocoaPods](http://cocoapods.org) (`pod 'GVUserDefaults'`) or drag the code in the GVUserDefaults subfolder to your project.
|
||||
|
||||
|
||||
## Issues and questions
|
||||
Have a bug? Please [create an issue on GitHub](https://github.com/gangverk/GVUserDefaults/issues)!
|
||||
|
||||
|
||||
## Contributing
|
||||
GVUserDefaults is an open source project and your contribution is very much appreciated.
|
||||
|
||||
1. Check for [open issues](https://github.com/gangverk/GVUserDefaults/issues) or [open a fresh issue](https://github.com/gangverk/GVUserDefaults/issues/new) to start a discussion around a feature idea or a bug.
|
||||
2. Fork the [repository on Github](https://github.com/gangverk/GVUserDefaults) and make your changes on the **develop** branch (or branch off of it). Please retain the code style that is used in the project.
|
||||
3. Write tests, make sure everything passes.
|
||||
4. Send a pull request.
|
||||
|
||||
|
||||
## License
|
||||
GVUserDefaults is available under the MIT license. See the LICENSE file for more info.
|
||||
|
||||
|
||||
## Thanks
|
||||
A huge thank you goes to [ADVUserDefaults](https://github.com/advantis/ADVUserDefaults) for its method of creating accessors for primitive types.
|
||||
Reference in New Issue
Block a user