网络层完善;tabbar。
This commit is contained in:
245
xplan-ios/Base/MVP/Model/NSObject+AutoCoding.m
Normal file
245
xplan-ios/Base/MVP/Model/NSObject+AutoCoding.m
Normal file
@@ -0,0 +1,245 @@
|
||||
//
|
||||
// NSObject+AutoCoding.m
|
||||
// YYMobileFramework
|
||||
//
|
||||
// Created by wuwei on 14/6/13.
|
||||
// Copyright (c) 2014年 YY Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSObject+AutoCoding.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wgnu"
|
||||
|
||||
static NSString *const AutocodingException = @"AutocodingException";
|
||||
|
||||
@implementation NSObject (AutoCoding)
|
||||
|
||||
+ (BOOL)supportsSecureCoding
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (instancetype)objectWithContentsOfFile:(NSString *)filePath
|
||||
{
|
||||
//load the file
|
||||
NSData *data = [NSData dataWithContentsOfFile:filePath];
|
||||
|
||||
//attempt to deserialise data as a plist
|
||||
id object = nil;
|
||||
if (data)
|
||||
{
|
||||
NSPropertyListFormat format;
|
||||
object = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:&format error:NULL];
|
||||
|
||||
//success?
|
||||
if (object)
|
||||
{
|
||||
//check if object is an NSCoded unarchive
|
||||
if ([object respondsToSelector:@selector(objectForKey:)] && [(NSDictionary *)object objectForKey:@"$archiver"])
|
||||
{
|
||||
object = [NSKeyedUnarchiver unarchiveObjectWithData:data];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//return raw data
|
||||
object = data;
|
||||
}
|
||||
}
|
||||
|
||||
//return object
|
||||
return object;
|
||||
}
|
||||
|
||||
- (BOOL)writeToFile:(NSString *)filePath atomically:(BOOL)useAuxiliaryFile
|
||||
{
|
||||
//note: NSData, NSDictionary and NSArray already implement this method
|
||||
//and do not save using NSCoding, however the objectWithContentsOfFile
|
||||
//method will correctly recover these objects anyway
|
||||
|
||||
//archive object
|
||||
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self];
|
||||
return [data writeToFile:filePath atomically:useAuxiliaryFile];
|
||||
}
|
||||
|
||||
+ (NSDictionary *)codableProperties
|
||||
{
|
||||
unsigned int propertyCount;
|
||||
__autoreleasing NSMutableDictionary *codableProperties = [NSMutableDictionary dictionary];
|
||||
objc_property_t *properties = class_copyPropertyList(self, &propertyCount);
|
||||
for (unsigned int i = 0; i < propertyCount; i++)
|
||||
{
|
||||
//get property name
|
||||
objc_property_t property = properties[i];
|
||||
const char *propertyName = property_getName(property);
|
||||
__autoreleasing NSString *key = @(propertyName);
|
||||
|
||||
//check if codable
|
||||
//get property type
|
||||
Class propertyClass = nil;
|
||||
char *typeEncoding = property_copyAttributeValue(property, "T");
|
||||
switch (typeEncoding[0])
|
||||
{
|
||||
case '@':
|
||||
{
|
||||
if (strlen(typeEncoding) >= 3)
|
||||
{
|
||||
char *className = strndup(typeEncoding + 2, strlen(typeEncoding) - 3);
|
||||
__autoreleasing NSString *name = @(className);
|
||||
NSRange range = [name rangeOfString:@"<"];
|
||||
if (range.location != NSNotFound)
|
||||
{
|
||||
name = [name substringToIndex:range.location];
|
||||
}
|
||||
propertyClass = NSClassFromString(name) ?: [NSObject class];
|
||||
free(className);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'c':
|
||||
case 'i':
|
||||
case 's':
|
||||
case 'l':
|
||||
case 'q':
|
||||
case 'C':
|
||||
case 'I':
|
||||
case 'S':
|
||||
case 'L':
|
||||
case 'Q':
|
||||
case 'f':
|
||||
case 'd':
|
||||
case 'B':
|
||||
{
|
||||
propertyClass = [NSNumber class];
|
||||
break;
|
||||
}
|
||||
case '{':
|
||||
{
|
||||
propertyClass = [NSValue class];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(typeEncoding);
|
||||
|
||||
if (propertyClass && [propertyClass conformsToProtocol:@protocol(NSSecureCoding)])
|
||||
{
|
||||
//check if there is a backing ivar
|
||||
char *ivar = property_copyAttributeValue(property, "V");
|
||||
if (ivar)
|
||||
{
|
||||
//check if ivar has KVC-compliant name
|
||||
__autoreleasing NSString *ivarName = @(ivar);
|
||||
if ([ivarName isEqualToString:key] || [ivarName isEqualToString:[@"_" stringByAppendingString:key]])
|
||||
{
|
||||
//no setter, but setValue:forKey: will still work
|
||||
codableProperties[key] = propertyClass;
|
||||
}
|
||||
free(ivar);
|
||||
}
|
||||
else
|
||||
{
|
||||
//check if property is dynamic and readwrite
|
||||
char *dynamic = property_copyAttributeValue(property, "D");
|
||||
char *readonly = property_copyAttributeValue(property, "R");
|
||||
if (dynamic && !readonly)
|
||||
{
|
||||
//no ivar, but setValue:forKey: will still work
|
||||
codableProperties[key] = propertyClass;
|
||||
}
|
||||
free(dynamic);
|
||||
free(readonly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(properties);
|
||||
return codableProperties;
|
||||
}
|
||||
|
||||
- (NSDictionary *)codableProperties
|
||||
{
|
||||
__autoreleasing NSDictionary *codableProperties = objc_getAssociatedObject([self class], _cmd);
|
||||
if (!codableProperties)
|
||||
{
|
||||
codableProperties = [NSMutableDictionary dictionary];
|
||||
Class subclass = [self class];
|
||||
while (subclass != [NSObject class])
|
||||
{
|
||||
[(NSMutableDictionary *)codableProperties addEntriesFromDictionary:[subclass codableProperties]];
|
||||
subclass = [subclass superclass];
|
||||
}
|
||||
codableProperties = [NSDictionary dictionaryWithDictionary:codableProperties];
|
||||
|
||||
//make the association atomically so that we don't need to bother with an @synchronize
|
||||
objc_setAssociatedObject([self class], _cmd, codableProperties, OBJC_ASSOCIATION_RETAIN);
|
||||
}
|
||||
return codableProperties;
|
||||
}
|
||||
|
||||
- (NSDictionary *)dictionaryRepresentation
|
||||
{
|
||||
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
||||
for (__unsafe_unretained NSString *key in [self codableProperties])
|
||||
{
|
||||
id value = [self valueForKey:key];
|
||||
if (value)
|
||||
dict[key] = value;
|
||||
else
|
||||
dict[key] = @"nil";
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
- (void)setWithCoder:(NSCoder *)aDecoder
|
||||
{
|
||||
BOOL secureAvailable = [aDecoder respondsToSelector:@selector(decodeObjectOfClass:forKey:)];
|
||||
BOOL secureSupported = [[self class] supportsSecureCoding];
|
||||
NSDictionary *properties = [self codableProperties];
|
||||
for (NSString *key in properties)
|
||||
{
|
||||
id object = nil;
|
||||
Class propertyClass = properties[key];
|
||||
if (secureAvailable)
|
||||
{
|
||||
if ([propertyClass isEqual:[NSMutableAttributedString class]]) {
|
||||
continue;
|
||||
}
|
||||
object = [aDecoder decodeObjectOfClass:propertyClass forKey:key];
|
||||
}
|
||||
else
|
||||
{
|
||||
if ([propertyClass isEqual:[NSMutableAttributedString class]]) {
|
||||
continue;
|
||||
}
|
||||
object = [aDecoder decodeObjectForKey:key];
|
||||
}
|
||||
if (object)
|
||||
{
|
||||
if (secureSupported && ![object isKindOfClass:propertyClass])
|
||||
{
|
||||
[NSException raise:AutocodingException format:@"Expected '%@' to be a %@, but was actually a %@", key, propertyClass, [object class]];
|
||||
}
|
||||
[self setValue:object forKey:key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder
|
||||
{
|
||||
[self setWithCoder:aDecoder];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder
|
||||
{
|
||||
for (NSString *key in [self codableProperties])
|
||||
{
|
||||
id object = [self valueForKey:key];
|
||||
if (object) [aCoder encodeObject:object forKey:key];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
Reference in New Issue
Block a user