This commit is contained in:
启星
2025-08-11 10:43:19 +08:00
commit fb2c58d96f
8839 changed files with 709982 additions and 0 deletions

View 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

View 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
View 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
View File

@@ -0,0 +1,99 @@
# GVUserDefaults - NSUserDefaults access via properties
[![Badge w/ Version](https://cocoapod-badges.herokuapp.com/v/GVUserDefaults/badge.png)](http://cocoadocs.org/docsets/GVUserDefaults)
[![Badge w/ Platform](https://cocoapod-badges.herokuapp.com/p/GVUserDefaults/badge.svg)](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.