Skip to content

Instantly share code, notes, and snippets.

@remirobert
Created April 27, 2015 14:19
Show Gist options
  • Save remirobert/fab8fe87e0edfc68a780 to your computer and use it in GitHub Desktop.
Save remirobert/fab8fe87e0edfc68a780 to your computer and use it in GitHub Desktop.
ModelContainer
//
// Model3D.m
// 3DModel
//
// Created by Remi Robert on 24/04/15.
// Copyright (c) 2015 Remi Robert. All rights reserved.
//
#import <objc/runtime.h>
#import "ModelContainer.h"
typedef enum : NSUInteger {
FloatType = 'f',
DoubleType = 'd',
BoolType = 'c',
IntType = 'i',
UnsignedLongType = 'q',
UnsignedLongLongType = 'Q',
LongType = 'l',
ShortType = 's',
UnsignedIntType = 'I',
ObjectType = '@',
} NSObjectValueType;
#pragma mark -
#pragma mark NSArray categorie
@implementation NSArray (ModelContainer)
- (void)saveForKey:(NSString *)key {
[self removeForKey:key];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self];
if (data) {
[[NSUserDefaults standardUserDefaults] setObject:data forKey:key];
}
}
+ (instancetype)instanceForKey:(NSString *)key {
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:key];
if (data) {
NSArray *models = [NSKeyedUnarchiver unarchiveObjectWithData:data];
return models;
}
return nil;
}
- (void)removeForKey:(NSString *)key {
[[NSUserDefaults standardUserDefaults] removeObjectForKey:key];
}
@end
@implementation ModelContainer
#pragma mark -
#pragma mark Object's properties
- (NSMutableDictionary *)propertiesForClass:(Class)class {
NSMutableDictionary *results = [[NSMutableDictionary alloc] init];
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList(class, &outCount);
for(i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
NSString *pname = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
NSString *pattrs = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];
pattrs = [[pattrs componentsSeparatedByString:@","] objectAtIndex:0];
pattrs = [pattrs substringFromIndex:1];
[results setObject:pattrs forKey:pname];
}
free(properties);
if ([class superclass] != [NSObject class]) {
[results addEntriesFromDictionary:[self propertiesForClass:[class superclass]]];
}
return results;
}
- (NSDictionary *)properties {
return [self propertiesForClass:[self class]];
}
#pragma mark -
#pragma mark Encode object's values
- (NSValue *)valueFromMethodSignature:(NSInvocation *)invocation withType:(char)type {
unsigned long long ullValue;
BOOL boolValue;
float floatValue;
double doubleValue;
NSInteger intValue;
unsigned long ulValue;
long longValue;
unsigned unsignedValue;
short shortValue;
[invocation invoke];
switch (type) {
case BoolType:
[invocation getReturnValue:&boolValue];
return [NSNumber numberWithBool:boolValue];
break;
case FloatType:
[invocation getReturnValue:&floatValue];
return [NSNumber numberWithFloat:floatValue];
case DoubleType:
[invocation getReturnValue:&doubleValue];
return [NSNumber numberWithDouble:doubleValue];
case IntType:
[invocation getReturnValue:&intValue];
return [NSNumber numberWithInteger:intValue];
case UnsignedLongType:
[invocation getReturnValue:&ulValue];
return [NSNumber numberWithUnsignedLong:ulValue];
case UnsignedLongLongType:
[invocation getReturnValue:&ullValue];
return [NSNumber numberWithUnsignedLongLong:ullValue];
case ShortType:
[invocation getReturnValue:&shortValue];
return [NSNumber numberWithShort:shortValue];
case UnsignedIntType:
[invocation getReturnValue:&unsignedValue];
return [NSNumber numberWithUnsignedInt:unsignedValue];
case LongType:
[invocation getReturnValue:&longValue];
return [NSNumber numberWithLong:longValue];
default:
break;
}
return nil;
}
- (void)encodeProperties:(NSDictionary*)properties withCoder:(NSCoder *)coder {
for (NSString *key in properties) {
NSString *type = [properties objectForKey:key];
id value;
NSMethodSignature *signature = [self methodSignatureForSelector:NSSelectorFromString(key)];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setSelector:NSSelectorFromString(key)];
[invocation setTarget:self];
if ([type characterAtIndex:0] == ObjectType) {
if ([[type componentsSeparatedByString:@"\""] count] > 1) {
Class class = NSClassFromString([[type componentsSeparatedByString:@"\""] objectAtIndex:1]);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
value = [self performSelector:NSSelectorFromString(key)];
#pragma clang diagnostic pop
if([class conformsToProtocol:@protocol(NSCoding)]){
[coder encodeObject:value forKey:key];
}
}
}
else {
[coder encodeObject:[self valueFromMethodSignature:invocation withType:[type characterAtIndex:0]] forKey:key];
}
}
}
#pragma mark -
#pragma mark Decode object's value
- (void)decodeProperties:(NSDictionary*)properties withCoder:(NSCoder *)coder {
for (NSString *key in properties) {
NSString *type = [properties objectForKey:key];
switch ([type characterAtIndex:0]) {
case ObjectType:
if ([[type componentsSeparatedByString:@"\""] count] > 1) {
Class class = NSClassFromString([[type componentsSeparatedByString:@"\""] objectAtIndex:1]);
if ([class conformsToProtocol:@protocol(NSCoding )]){
[self setValue:[coder decodeObjectForKey:key] forKey:key];
}
}
break;
case BoolType:
[self setValue:@([[coder decodeObjectForKey:key] boolValue]) forKey:key];
break;
case FloatType:
[self setValue:@([[coder decodeObjectForKey:key] floatValue]) forKey:key];
break;
case DoubleType:
[self setValue:@([[coder decodeObjectForKey:key] doubleValue]) forKey:key];
break;
case IntType:
[self setValue:@([[coder decodeObjectForKey:key] intValue]) forKey:key];
break;
case UnsignedLongType:
[self setValue:@([[coder decodeObjectForKey:key] unsignedLongValue]) forKey:key];
break;
case UnsignedLongLongType:
[self setValue:@([[coder decodeObjectForKey:key] unsignedLongLongValue]) forKey:key];
break;
case LongType:
[self setValue:@([[coder decodeObjectForKey:key] longValue]) forKey:key];
break;
case UnsignedIntType:
[self setValue:@([[coder decodeObjectForKey:key] unsignedIntValue]) forKey:key];
break;
case ShortType:
[self setValue:@([[coder decodeObjectForKey:key] shortValue]) forKey:key];
break;
default:
break;
}
}
}
#pragma mark -
#pragma mark NSCoding
- (void)encodeWithCoder:(NSCoder *)aCoder {
[self encodeProperties:[self properties] withCoder:aCoder];
}
- (id)initWithCoder:(NSCoder *)aDecoder {
[self decodeProperties:[self properties] withCoder:aDecoder];
return self;
}
#pragma mark -
#pragma mark Persistance management
- (void)remove {
if (self.key) {
[[NSUserDefaults standardUserDefaults] removeObjectForKey:self.key];
}
}
+ (void)removeForKey:(NSString *)key {
[[NSUserDefaults standardUserDefaults] removeObjectForKey:key];
}
- (void)update {
if (self.key) {
[self remove];
[self save];
}
}
- (void)saveForKey:(NSString *)key {
self.key = key;
[self save];
}
- (void)save {
if (self.key) {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:@[self]];
if (data) {
[[NSUserDefaults standardUserDefaults] setObject:data forKey:self.key];
}
}
}
+ (instancetype)instanceObjectForKey:(NSString *)key {
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:key];
if (data) {
NSArray *models = [NSKeyedUnarchiver unarchiveObjectWithData:data];
id object = [models firstObject];
if (object || ![object isKindOfClass:[ModelContainer class]]) {
((ModelContainer *)object).key = key;
return object;
}
}
return nil;
}
+ (NSArray *)instanceObjectsForKey:(NSString *)key {
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:key];
if (data) {
NSArray *models = [NSKeyedUnarchiver unarchiveObjectWithData:data];
return models;
}
return nil;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment