4
This commit is contained in:
27
Pods/MJExtension/MJExtension/MJExtension.h
generated
Normal file
27
Pods/MJExtension/MJExtension/MJExtension.h
generated
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// MJExtension.h
|
||||
// MJExtension
|
||||
//
|
||||
// Created by mj on 14-1-15.
|
||||
// Copyright (c) 2014年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "NSObject+MJCoding.h"
|
||||
#import "NSObject+MJProperty.h"
|
||||
#import "NSObject+MJClass.h"
|
||||
#import "NSObject+MJKeyValue.h"
|
||||
#import "NSString+MJExtension.h"
|
||||
#import "MJExtensionConst.h"
|
||||
|
||||
#import "MJFoundation.h"
|
||||
|
||||
//! Project version number for MJExtension.
|
||||
FOUNDATION_EXPORT double MJExtensionVersionNumber;
|
||||
|
||||
//! Project version string for MJExtension.
|
||||
FOUNDATION_EXPORT const unsigned char MJExtensionVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <MJExtension/PublicHeader.h>
|
||||
|
||||
|
||||
111
Pods/MJExtension/MJExtension/MJExtensionConst.h
generated
Normal file
111
Pods/MJExtension/MJExtension/MJExtensionConst.h
generated
Normal file
@@ -0,0 +1,111 @@
|
||||
|
||||
#ifndef __MJExtensionConst__H__
|
||||
#define __MJExtensionConst__H__
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#ifndef MJ_LOCK
|
||||
#define MJ_LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
|
||||
#endif
|
||||
|
||||
#ifndef MJ_UNLOCK
|
||||
#define MJ_UNLOCK(lock) dispatch_semaphore_signal(lock);
|
||||
#endif
|
||||
|
||||
// 信号量
|
||||
#define MJExtensionSemaphoreCreate \
|
||||
extern dispatch_semaphore_t mje_signalSemaphore; \
|
||||
extern dispatch_once_t mje_onceTokenSemaphore; \
|
||||
dispatch_once(&mje_onceTokenSemaphore, ^{ \
|
||||
mje_signalSemaphore = dispatch_semaphore_create(1); \
|
||||
});
|
||||
|
||||
// 过期
|
||||
#define MJExtensionDeprecated(instead) NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead)
|
||||
|
||||
// 构建错误
|
||||
#define MJExtensionBuildError(clazz, msg) \
|
||||
NSError *error = [NSError errorWithDomain:msg code:250 userInfo:nil]; \
|
||||
[clazz setMj_error:error];
|
||||
|
||||
// 日志输出
|
||||
#ifdef DEBUG
|
||||
#define MJExtensionLog(...) NSLog(__VA_ARGS__)
|
||||
#else
|
||||
#define MJExtensionLog(...)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* 断言
|
||||
* @param condition 条件
|
||||
* @param returnValue 返回值
|
||||
*/
|
||||
#define MJExtensionAssertError(condition, returnValue, clazz, msg) \
|
||||
[clazz setMj_error:nil]; \
|
||||
if ((condition) == NO) { \
|
||||
MJExtensionBuildError(clazz, msg); \
|
||||
return returnValue;\
|
||||
}
|
||||
|
||||
#define MJExtensionAssert2(condition, returnValue) \
|
||||
if ((condition) == NO) return returnValue;
|
||||
|
||||
/**
|
||||
* 断言
|
||||
* @param condition 条件
|
||||
*/
|
||||
#define MJExtensionAssert(condition) MJExtensionAssert2(condition, )
|
||||
|
||||
/**
|
||||
* 断言
|
||||
* @param param 参数
|
||||
* @param returnValue 返回值
|
||||
*/
|
||||
#define MJExtensionAssertParamNotNil2(param, returnValue) \
|
||||
MJExtensionAssert2((param) != nil, returnValue)
|
||||
|
||||
/**
|
||||
* 断言
|
||||
* @param param 参数
|
||||
*/
|
||||
#define MJExtensionAssertParamNotNil(param) MJExtensionAssertParamNotNil2(param, )
|
||||
|
||||
/**
|
||||
* 打印所有的属性
|
||||
*/
|
||||
#define MJLogAllIvars \
|
||||
- (NSString *)description \
|
||||
{ \
|
||||
return [self mj_keyValues].description; \
|
||||
}
|
||||
#define MJExtensionLogAllProperties MJLogAllIvars
|
||||
|
||||
/** 仅在 Debugger 展示所有的属性 */
|
||||
#define MJImplementDebugDescription \
|
||||
- (NSString *)debugDescription \
|
||||
{ \
|
||||
return [self mj_keyValues].debugDescription; \
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型(属性类型)
|
||||
*/
|
||||
FOUNDATION_EXPORT NSString *const MJPropertyTypeInt;
|
||||
FOUNDATION_EXPORT NSString *const MJPropertyTypeShort;
|
||||
FOUNDATION_EXPORT NSString *const MJPropertyTypeFloat;
|
||||
FOUNDATION_EXPORT NSString *const MJPropertyTypeDouble;
|
||||
FOUNDATION_EXPORT NSString *const MJPropertyTypeLong;
|
||||
FOUNDATION_EXPORT NSString *const MJPropertyTypeLongLong;
|
||||
FOUNDATION_EXPORT NSString *const MJPropertyTypeChar;
|
||||
FOUNDATION_EXPORT NSString *const MJPropertyTypeBOOL1;
|
||||
FOUNDATION_EXPORT NSString *const MJPropertyTypeBOOL2;
|
||||
FOUNDATION_EXPORT NSString *const MJPropertyTypePointer;
|
||||
|
||||
FOUNDATION_EXPORT NSString *const MJPropertyTypeIvar;
|
||||
FOUNDATION_EXPORT NSString *const MJPropertyTypeMethod;
|
||||
FOUNDATION_EXPORT NSString *const MJPropertyTypeBlock;
|
||||
FOUNDATION_EXPORT NSString *const MJPropertyTypeClass;
|
||||
FOUNDATION_EXPORT NSString *const MJPropertyTypeSEL;
|
||||
FOUNDATION_EXPORT NSString *const MJPropertyTypeId;
|
||||
|
||||
#endif
|
||||
27
Pods/MJExtension/MJExtension/MJExtensionConst.m
generated
Normal file
27
Pods/MJExtension/MJExtension/MJExtensionConst.m
generated
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef __MJExtensionConst__M__
|
||||
#define __MJExtensionConst__M__
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* 成员变量类型(属性类型)
|
||||
*/
|
||||
NSString *const MJPropertyTypeInt = @"i";
|
||||
NSString *const MJPropertyTypeShort = @"s";
|
||||
NSString *const MJPropertyTypeFloat = @"f";
|
||||
NSString *const MJPropertyTypeDouble = @"d";
|
||||
NSString *const MJPropertyTypeLong = @"l";
|
||||
NSString *const MJPropertyTypeLongLong = @"q";
|
||||
NSString *const MJPropertyTypeChar = @"c";
|
||||
NSString *const MJPropertyTypeBOOL1 = @"c";
|
||||
NSString *const MJPropertyTypeBOOL2 = @"b";
|
||||
NSString *const MJPropertyTypePointer = @"*";
|
||||
|
||||
NSString *const MJPropertyTypeIvar = @"^{objc_ivar=}";
|
||||
NSString *const MJPropertyTypeMethod = @"^{objc_method=}";
|
||||
NSString *const MJPropertyTypeBlock = @"@?";
|
||||
NSString *const MJPropertyTypeClass = @"#";
|
||||
NSString *const MJPropertyTypeSEL = @":";
|
||||
NSString *const MJPropertyTypeId = @"@";
|
||||
|
||||
#endif
|
||||
16
Pods/MJExtension/MJExtension/MJFoundation.h
generated
Normal file
16
Pods/MJExtension/MJExtension/MJFoundation.h
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// MJFoundation.h
|
||||
// MJExtensionExample
|
||||
//
|
||||
// Created by MJ Lee on 14/7/16.
|
||||
// Copyright (c) 2014年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface MJFoundation : NSObject
|
||||
|
||||
+ (BOOL)isClassFromFoundation:(Class)c;
|
||||
+ (BOOL)isFromNSObjectProtocolProperty:(NSString *)propertyName;
|
||||
|
||||
@end
|
||||
70
Pods/MJExtension/MJExtension/MJFoundation.m
generated
Normal file
70
Pods/MJExtension/MJExtension/MJFoundation.m
generated
Normal file
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// MJFoundation.m
|
||||
// MJExtensionExample
|
||||
//
|
||||
// Created by MJ Lee on 14/7/16.
|
||||
// Copyright (c) 2014年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJFoundation.h"
|
||||
#import "MJExtensionConst.h"
|
||||
#import <CoreData/CoreData.h>
|
||||
#import "objc/runtime.h"
|
||||
|
||||
@implementation MJFoundation
|
||||
|
||||
+ (BOOL)isClassFromFoundation:(Class)c
|
||||
{
|
||||
if (c == [NSObject class] || c == [NSManagedObject class]) return YES;
|
||||
|
||||
static NSSet *foundationClasses;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
// 集合中没有NSObject,因为几乎所有的类都是继承自NSObject,具体是不是NSObject需要特殊判断
|
||||
foundationClasses = [NSSet setWithObjects:
|
||||
[NSURL class],
|
||||
[NSDate class],
|
||||
[NSValue class],
|
||||
[NSData class],
|
||||
[NSError class],
|
||||
[NSArray class],
|
||||
[NSDictionary class],
|
||||
[NSString class],
|
||||
[NSAttributedString class], nil];
|
||||
});
|
||||
|
||||
__block BOOL result = NO;
|
||||
[foundationClasses enumerateObjectsUsingBlock:^(Class foundationClass, BOOL *stop) {
|
||||
if ([c isSubclassOfClass:foundationClass]) {
|
||||
result = YES;
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (BOOL)isFromNSObjectProtocolProperty:(NSString *)propertyName
|
||||
{
|
||||
if (!propertyName) return NO;
|
||||
|
||||
static NSSet<NSString *> *objectProtocolPropertyNames;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
unsigned int count = 0;
|
||||
objc_property_t *propertyList = protocol_copyPropertyList(@protocol(NSObject), &count);
|
||||
NSMutableSet *propertyNames = [NSMutableSet setWithCapacity:count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
objc_property_t property = propertyList[i];
|
||||
NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
|
||||
if (propertyName) {
|
||||
[propertyNames addObject:propertyName];
|
||||
}
|
||||
}
|
||||
objectProtocolPropertyNames = [propertyNames copy];
|
||||
free(propertyList);
|
||||
});
|
||||
|
||||
return [objectProtocolPropertyNames containsObject:propertyName];
|
||||
}
|
||||
|
||||
@end
|
||||
53
Pods/MJExtension/MJExtension/MJProperty.h
generated
Normal file
53
Pods/MJExtension/MJExtension/MJProperty.h
generated
Normal file
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// MJProperty.h
|
||||
// MJExtensionExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/17.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
// 包装一个成员属性
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <objc/runtime.h>
|
||||
#import "MJPropertyType.h"
|
||||
#import "MJPropertyKey.h"
|
||||
|
||||
/**
|
||||
* 包装一个成员
|
||||
*/
|
||||
@interface MJProperty : NSObject
|
||||
/** 成员属性 */
|
||||
@property (nonatomic, assign) objc_property_t property;
|
||||
/** 成员属性的名字 */
|
||||
@property (nonatomic, readonly) NSString *name;
|
||||
|
||||
/** 成员属性的类型 */
|
||||
@property (nonatomic, readonly) MJPropertyType *type;
|
||||
/** 成员属性来源于哪个类(可能是父类) */
|
||||
@property (nonatomic, assign) Class srcClass;
|
||||
|
||||
/**** 同一个成员属性 - 父类和子类的行为可能不一致(originKey、propertyKeys、objectClassInArray) ****/
|
||||
/** 设置最原始的key */
|
||||
- (void)setOriginKey:(id)originKey forClass:(Class)c;
|
||||
/** 对应着字典中的多级key(里面存放的数组,数组里面都是MJPropertyKey对象) */
|
||||
- (NSArray *)propertyKeysForClass:(Class)c;
|
||||
|
||||
/** 模型数组中的模型类型 */
|
||||
- (void)setObjectClassInArray:(Class)objectClass forClass:(Class)c;
|
||||
- (Class)objectClassInArrayForClass:(Class)c;
|
||||
/**** 同一个成员变量 - 父类和子类的行为可能不一致(key、keys、objectClassInArray) ****/
|
||||
|
||||
/**
|
||||
* 设置object的成员变量值
|
||||
*/
|
||||
- (void)setValue:(id)value forObject:(id)object;
|
||||
/**
|
||||
* 得到object的成员属性值
|
||||
*/
|
||||
- (id)valueForObject:(id)object;
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
+ (instancetype)cachedPropertyWithProperty:(objc_property_t)property;
|
||||
|
||||
@end
|
||||
211
Pods/MJExtension/MJExtension/MJProperty.m
generated
Normal file
211
Pods/MJExtension/MJExtension/MJProperty.m
generated
Normal file
@@ -0,0 +1,211 @@
|
||||
//
|
||||
// MJProperty.m
|
||||
// MJExtensionExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/17.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJProperty.h"
|
||||
#import "MJFoundation.h"
|
||||
#import "MJExtensionConst.h"
|
||||
#import <objc/message.h>
|
||||
#include "TargetConditionals.h"
|
||||
|
||||
@interface MJProperty()
|
||||
@property (strong, nonatomic) NSMutableDictionary *propertyKeysDict;
|
||||
@property (strong, nonatomic) NSMutableDictionary *objectClassInArrayDict;
|
||||
@property (strong, nonatomic) dispatch_semaphore_t propertyKeysLock;
|
||||
@property (strong, nonatomic) dispatch_semaphore_t objectClassInArrayLock;
|
||||
@end
|
||||
|
||||
@implementation MJProperty
|
||||
|
||||
#pragma mark - 初始化
|
||||
- (instancetype)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_propertyKeysDict = [NSMutableDictionary dictionary];
|
||||
_objectClassInArrayDict = [NSMutableDictionary dictionary];
|
||||
_propertyKeysLock = dispatch_semaphore_create(1);
|
||||
_objectClassInArrayLock = dispatch_semaphore_create(1);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - 缓存
|
||||
+ (instancetype)cachedPropertyWithProperty:(objc_property_t)property
|
||||
{
|
||||
MJProperty *propertyObj = objc_getAssociatedObject(self, property);
|
||||
if (propertyObj == nil) {
|
||||
propertyObj = [[self alloc] init];
|
||||
propertyObj.property = property;
|
||||
objc_setAssociatedObject(self, property, propertyObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
return propertyObj;
|
||||
}
|
||||
|
||||
#pragma mark - 公共方法
|
||||
- (void)setProperty:(objc_property_t)property
|
||||
{
|
||||
_property = property;
|
||||
|
||||
MJExtensionAssertParamNotNil(property);
|
||||
|
||||
// 1.属性名
|
||||
_name = @(property_getName(property));
|
||||
|
||||
// 2.成员类型
|
||||
NSString *attrs = @(property_getAttributes(property));
|
||||
NSUInteger dotLoc = [attrs rangeOfString:@","].location;
|
||||
NSString *code = nil;
|
||||
NSUInteger loc = 1;
|
||||
if (dotLoc == NSNotFound) { // 没有,
|
||||
code = [attrs substringFromIndex:loc];
|
||||
} else {
|
||||
code = [attrs substringWithRange:NSMakeRange(loc, dotLoc - loc)];
|
||||
}
|
||||
_type = [MJPropertyType cachedTypeWithCode:code];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得成员变量的值
|
||||
*/
|
||||
- (id)valueForObject:(id)object
|
||||
{
|
||||
if (self.type.KVCDisabled) return [NSNull null];
|
||||
|
||||
id value = [object valueForKey:self.name];
|
||||
|
||||
// 32位BOOL类型转换json后成Int类型
|
||||
/** https://github.com/CoderMJLee/MJExtension/issues/545 */
|
||||
// 32 bit device OR 32 bit Simulator
|
||||
#if defined(__arm__) || (TARGET_OS_SIMULATOR && !__LP64__)
|
||||
if (self.type.isBoolType) {
|
||||
value = @([(NSNumber *)value boolValue]);
|
||||
}
|
||||
#endif
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置成员变量的值
|
||||
*/
|
||||
- (void)setValue:(id)value forObject:(id)object
|
||||
{
|
||||
if (self.type.KVCDisabled || value == nil) return;
|
||||
[object setValue:value forKey:self.name];
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过字符串key创建对应的keys
|
||||
*/
|
||||
- (NSArray *)propertyKeysWithStringKey:(NSString *)stringKey
|
||||
{
|
||||
if (stringKey.length == 0) return nil;
|
||||
|
||||
NSMutableArray *propertyKeys = [NSMutableArray array];
|
||||
// 如果有多级映射
|
||||
NSArray *oldKeys = [stringKey componentsSeparatedByString:@"."];
|
||||
|
||||
for (NSString *oldKey in oldKeys) {
|
||||
NSUInteger start = [oldKey rangeOfString:@"["].location;
|
||||
if (start != NSNotFound) { // 有索引的key
|
||||
NSString *prefixKey = [oldKey substringToIndex:start];
|
||||
NSString *indexKey = prefixKey;
|
||||
if (prefixKey.length) {
|
||||
MJPropertyKey *propertyKey = [[MJPropertyKey alloc] init];
|
||||
propertyKey.name = prefixKey;
|
||||
[propertyKeys addObject:propertyKey];
|
||||
|
||||
indexKey = [oldKey stringByReplacingOccurrencesOfString:prefixKey withString:@""];
|
||||
}
|
||||
|
||||
/** 解析索引 **/
|
||||
// 元素
|
||||
NSArray *cmps = [[indexKey stringByReplacingOccurrencesOfString:@"[" withString:@""] componentsSeparatedByString:@"]"];
|
||||
for (NSInteger i = 0; i<cmps.count - 1; i++) {
|
||||
MJPropertyKey *subPropertyKey = [[MJPropertyKey alloc] init];
|
||||
subPropertyKey.type = MJPropertyKeyTypeArray;
|
||||
subPropertyKey.name = cmps[i];
|
||||
[propertyKeys addObject:subPropertyKey];
|
||||
}
|
||||
} else { // 没有索引的key
|
||||
MJPropertyKey *propertyKey = [[MJPropertyKey alloc] init];
|
||||
propertyKey.name = oldKey;
|
||||
[propertyKeys addObject:propertyKey];
|
||||
}
|
||||
}
|
||||
|
||||
return propertyKeys;
|
||||
}
|
||||
|
||||
/** 对应着字典中的key */
|
||||
- (void)setOriginKey:(id)originKey forClass:(Class)c
|
||||
{
|
||||
if ([originKey isKindOfClass:[NSString class]]) { // 字符串类型的key
|
||||
NSArray *propertyKeys = [self propertyKeysWithStringKey:originKey];
|
||||
if (propertyKeys.count) {
|
||||
[self setPropertyKeys:@[propertyKeys] forClass:c];
|
||||
}
|
||||
} else if ([originKey isKindOfClass:[NSArray class]]) {
|
||||
NSMutableArray *keyses = [NSMutableArray array];
|
||||
for (NSString *stringKey in originKey) {
|
||||
NSArray *propertyKeys = [self propertyKeysWithStringKey:stringKey];
|
||||
if (propertyKeys.count) {
|
||||
[keyses addObject:propertyKeys];
|
||||
}
|
||||
}
|
||||
if (keyses.count) {
|
||||
[self setPropertyKeys:keyses forClass:c];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 对应着字典中的多级key */
|
||||
- (void)setPropertyKeys:(NSArray *)propertyKeys forClass:(Class)c
|
||||
{
|
||||
if (propertyKeys.count == 0) return;
|
||||
NSString *key = NSStringFromClass(c);
|
||||
if (!key) return;
|
||||
|
||||
MJ_LOCK(self.propertyKeysLock);
|
||||
self.propertyKeysDict[key] = propertyKeys;
|
||||
MJ_UNLOCK(self.propertyKeysLock);
|
||||
}
|
||||
|
||||
- (NSArray *)propertyKeysForClass:(Class)c
|
||||
{
|
||||
NSString *key = NSStringFromClass(c);
|
||||
if (!key) return nil;
|
||||
|
||||
MJ_LOCK(self.propertyKeysLock);
|
||||
NSArray *propertyKeys = self.propertyKeysDict[key];
|
||||
MJ_UNLOCK(self.propertyKeysLock);
|
||||
return propertyKeys;
|
||||
}
|
||||
|
||||
/** 模型数组中的模型类型 */
|
||||
- (void)setObjectClassInArray:(Class)objectClass forClass:(Class)c
|
||||
{
|
||||
if (!objectClass) return;
|
||||
NSString *key = NSStringFromClass(c);
|
||||
if (!key) return;
|
||||
|
||||
MJ_LOCK(self.objectClassInArrayLock);
|
||||
self.objectClassInArrayDict[key] = objectClass;
|
||||
MJ_UNLOCK(self.objectClassInArrayLock);
|
||||
}
|
||||
|
||||
- (Class)objectClassInArrayForClass:(Class)c
|
||||
{
|
||||
NSString *key = NSStringFromClass(c);
|
||||
if (!key) return nil;
|
||||
|
||||
MJ_LOCK(self.objectClassInArrayLock);
|
||||
Class objectClass = self.objectClassInArrayDict[key];
|
||||
MJ_UNLOCK(self.objectClassInArrayLock);
|
||||
return objectClass;
|
||||
}
|
||||
@end
|
||||
30
Pods/MJExtension/MJExtension/MJPropertyKey.h
generated
Normal file
30
Pods/MJExtension/MJExtension/MJPropertyKey.h
generated
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// MJPropertyKey.h
|
||||
// MJExtensionExample
|
||||
//
|
||||
// Created by MJ Lee on 15/8/11.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef enum {
|
||||
MJPropertyKeyTypeDictionary = 0, // 字典的key
|
||||
MJPropertyKeyTypeArray // 数组的key
|
||||
} MJPropertyKeyType;
|
||||
|
||||
/**
|
||||
* 属性的key
|
||||
*/
|
||||
@interface MJPropertyKey : NSObject
|
||||
/** key的名字 */
|
||||
@property (copy, nonatomic) NSString *name;
|
||||
/** key的种类,可能是@"10",可能是@"age" */
|
||||
@property (assign, nonatomic) MJPropertyKeyType type;
|
||||
|
||||
/**
|
||||
* 根据当前的key,也就是name,从object(字典或者数组)中取值
|
||||
*/
|
||||
- (id)valueInObject:(id)object;
|
||||
|
||||
@end
|
||||
25
Pods/MJExtension/MJExtension/MJPropertyKey.m
generated
Normal file
25
Pods/MJExtension/MJExtension/MJPropertyKey.m
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// MJPropertyKey.m
|
||||
// MJExtensionExample
|
||||
//
|
||||
// Created by MJ Lee on 15/8/11.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJPropertyKey.h"
|
||||
|
||||
@implementation MJPropertyKey
|
||||
|
||||
- (id)valueInObject:(id)object
|
||||
{
|
||||
if ([object isKindOfClass:[NSDictionary class]] && self.type == MJPropertyKeyTypeDictionary) {
|
||||
return object[self.name];
|
||||
} else if ([object isKindOfClass:[NSArray class]] && self.type == MJPropertyKeyTypeArray) {
|
||||
NSArray *array = object;
|
||||
NSUInteger index = self.name.intValue;
|
||||
if (index < array.count) return array[index];
|
||||
return nil;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
@end
|
||||
39
Pods/MJExtension/MJExtension/MJPropertyType.h
generated
Executable file
39
Pods/MJExtension/MJExtension/MJPropertyType.h
generated
Executable file
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// MJPropertyType.h
|
||||
// MJExtension
|
||||
//
|
||||
// Created by mj on 14-1-15.
|
||||
// Copyright (c) 2014年 小码哥. All rights reserved.
|
||||
// 包装一种类型
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* 包装一种类型
|
||||
*/
|
||||
@interface MJPropertyType : NSObject
|
||||
/** 类型标识符 */
|
||||
@property (nonatomic, copy) NSString *code;
|
||||
|
||||
/** 是否为id类型 */
|
||||
@property (nonatomic, readonly, getter=isIdType) BOOL idType;
|
||||
|
||||
/** 是否为基本数字类型:int、float等 */
|
||||
@property (nonatomic, readonly, getter=isNumberType) BOOL numberType;
|
||||
|
||||
/** 是否为BOOL类型 */
|
||||
@property (nonatomic, readonly, getter=isBoolType) BOOL boolType;
|
||||
|
||||
/** 对象类型(如果是基本数据类型,此值为nil) */
|
||||
@property (nonatomic, readonly) Class typeClass;
|
||||
|
||||
/** 类型是否来自于Foundation框架,比如NSString、NSArray */
|
||||
@property (nonatomic, readonly, getter = isFromFoundation) BOOL fromFoundation;
|
||||
/** 类型是否不支持KVC */
|
||||
@property (nonatomic, readonly, getter = isKVCDisabled) BOOL KVCDisabled;
|
||||
|
||||
/**
|
||||
* 获得缓存的类型对象
|
||||
*/
|
||||
+ (instancetype)cachedTypeWithCode:(NSString *)code;
|
||||
@end
|
||||
71
Pods/MJExtension/MJExtension/MJPropertyType.m
generated
Executable file
71
Pods/MJExtension/MJExtension/MJPropertyType.m
generated
Executable file
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// MJPropertyType.m
|
||||
// MJExtension
|
||||
//
|
||||
// Created by mj on 14-1-15.
|
||||
// Copyright (c) 2014年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MJPropertyType.h"
|
||||
#import "MJExtension.h"
|
||||
#import "MJFoundation.h"
|
||||
#import "MJExtensionConst.h"
|
||||
|
||||
@implementation MJPropertyType
|
||||
|
||||
+ (instancetype)cachedTypeWithCode:(NSString *)code
|
||||
{
|
||||
MJExtensionAssertParamNotNil2(code, nil);
|
||||
|
||||
static NSMutableDictionary *types;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
types = [NSMutableDictionary dictionary];
|
||||
});
|
||||
|
||||
MJPropertyType *type = types[code];
|
||||
if (type == nil) {
|
||||
type = [[self alloc] init];
|
||||
type.code = code;
|
||||
types[code] = type;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
#pragma mark - 公共方法
|
||||
- (void)setCode:(NSString *)code
|
||||
{
|
||||
_code = code;
|
||||
|
||||
MJExtensionAssertParamNotNil(code);
|
||||
|
||||
if ([code isEqualToString:MJPropertyTypeId]) {
|
||||
_idType = YES;
|
||||
} else if (code.length == 0) {
|
||||
_KVCDisabled = YES;
|
||||
} else if (code.length > 3 && [code hasPrefix:@"@\""]) {
|
||||
// 去掉@"和",截取中间的类型名称
|
||||
_code = [code substringWithRange:NSMakeRange(2, code.length - 3)];
|
||||
_typeClass = NSClassFromString(_code);
|
||||
_fromFoundation = [MJFoundation isClassFromFoundation:_typeClass];
|
||||
_numberType = [_typeClass isSubclassOfClass:[NSNumber class]];
|
||||
|
||||
} else if ([code isEqualToString:MJPropertyTypeSEL] ||
|
||||
[code isEqualToString:MJPropertyTypeIvar] ||
|
||||
[code isEqualToString:MJPropertyTypeMethod]) {
|
||||
_KVCDisabled = YES;
|
||||
}
|
||||
|
||||
// 是否为数字类型
|
||||
NSString *lowerCode = _code.lowercaseString;
|
||||
NSArray *numberTypes = @[MJPropertyTypeInt, MJPropertyTypeShort, MJPropertyTypeBOOL1, MJPropertyTypeBOOL2, MJPropertyTypeFloat, MJPropertyTypeDouble, MJPropertyTypeLong, MJPropertyTypeLongLong, MJPropertyTypeChar];
|
||||
if ([numberTypes containsObject:lowerCode]) {
|
||||
_numberType = YES;
|
||||
|
||||
if ([lowerCode isEqualToString:MJPropertyTypeBOOL1]
|
||||
|| [lowerCode isEqualToString:MJPropertyTypeBOOL2]) {
|
||||
_boolType = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
@end
|
||||
90
Pods/MJExtension/MJExtension/NSObject+MJClass.h
generated
Normal file
90
Pods/MJExtension/MJExtension/NSObject+MJClass.h
generated
Normal file
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// NSObject+MJClass.h
|
||||
// MJExtensionExample
|
||||
//
|
||||
// Created by MJ Lee on 15/8/11.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* 遍历所有类的block(父类)
|
||||
*/
|
||||
typedef void (^MJClassesEnumeration)(Class c, BOOL *stop);
|
||||
|
||||
/** 这个数组中的属性名才会进行字典和模型的转换 */
|
||||
typedef NSArray * (^MJAllowedPropertyNames)(void);
|
||||
/** 这个数组中的属性名才会进行归档 */
|
||||
typedef NSArray * (^MJAllowedCodingPropertyNames)(void);
|
||||
|
||||
/** 这个数组中的属性名将会被忽略:不进行字典和模型的转换 */
|
||||
typedef NSArray * (^MJIgnoredPropertyNames)(void);
|
||||
/** 这个数组中的属性名将会被忽略:不进行归档 */
|
||||
typedef NSArray * (^MJIgnoredCodingPropertyNames)(void);
|
||||
|
||||
/**
|
||||
* 类相关的扩展
|
||||
*/
|
||||
@interface NSObject (MJClass)
|
||||
/**
|
||||
* 遍历所有的类
|
||||
*/
|
||||
+ (void)mj_enumerateClasses:(MJClassesEnumeration)enumeration;
|
||||
+ (void)mj_enumerateAllClasses:(MJClassesEnumeration)enumeration;
|
||||
|
||||
#pragma mark - 属性白名单配置
|
||||
/**
|
||||
* 这个数组中的属性名才会进行字典和模型的转换
|
||||
*
|
||||
* @param allowedPropertyNames 这个数组中的属性名才会进行字典和模型的转换
|
||||
*/
|
||||
+ (void)mj_setupAllowedPropertyNames:(MJAllowedPropertyNames)allowedPropertyNames;
|
||||
|
||||
/**
|
||||
* 这个数组中的属性名才会进行字典和模型的转换
|
||||
*/
|
||||
+ (NSMutableArray *)mj_totalAllowedPropertyNames;
|
||||
|
||||
#pragma mark - 属性黑名单配置
|
||||
/**
|
||||
* 这个数组中的属性名将会被忽略:不进行字典和模型的转换
|
||||
*
|
||||
* @param ignoredPropertyNames 这个数组中的属性名将会被忽略:不进行字典和模型的转换
|
||||
*/
|
||||
+ (void)mj_setupIgnoredPropertyNames:(MJIgnoredPropertyNames)ignoredPropertyNames;
|
||||
|
||||
/**
|
||||
* 这个数组中的属性名将会被忽略:不进行字典和模型的转换
|
||||
*/
|
||||
+ (NSMutableArray *)mj_totalIgnoredPropertyNames;
|
||||
|
||||
#pragma mark - 归档属性白名单配置
|
||||
/**
|
||||
* 这个数组中的属性名才会进行归档
|
||||
*
|
||||
* @param allowedCodingPropertyNames 这个数组中的属性名才会进行归档
|
||||
*/
|
||||
+ (void)mj_setupAllowedCodingPropertyNames:(MJAllowedCodingPropertyNames)allowedCodingPropertyNames;
|
||||
|
||||
/**
|
||||
* 这个数组中的属性名才会进行字典和模型的转换
|
||||
*/
|
||||
+ (NSMutableArray *)mj_totalAllowedCodingPropertyNames;
|
||||
|
||||
#pragma mark - 归档属性黑名单配置
|
||||
/**
|
||||
* 这个数组中的属性名将会被忽略:不进行归档
|
||||
*
|
||||
* @param ignoredCodingPropertyNames 这个数组中的属性名将会被忽略:不进行归档
|
||||
*/
|
||||
+ (void)mj_setupIgnoredCodingPropertyNames:(MJIgnoredCodingPropertyNames)ignoredCodingPropertyNames;
|
||||
|
||||
/**
|
||||
* 这个数组中的属性名将会被忽略:不进行归档
|
||||
*/
|
||||
+ (NSMutableArray *)mj_totalIgnoredCodingPropertyNames;
|
||||
|
||||
#pragma mark - 内部使用
|
||||
+ (void)mj_setupBlockReturnValue:(id (^)(void))block key:(const char *)key;
|
||||
@end
|
||||
174
Pods/MJExtension/MJExtension/NSObject+MJClass.m
generated
Normal file
174
Pods/MJExtension/MJExtension/NSObject+MJClass.m
generated
Normal file
@@ -0,0 +1,174 @@
|
||||
//
|
||||
// NSObject+MJClass.m
|
||||
// MJExtensionExample
|
||||
//
|
||||
// Created by MJ Lee on 15/8/11.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSObject+MJClass.h"
|
||||
#import "NSObject+MJCoding.h"
|
||||
#import "NSObject+MJKeyValue.h"
|
||||
#import "MJFoundation.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
static const char MJAllowedPropertyNamesKey = '\0';
|
||||
static const char MJIgnoredPropertyNamesKey = '\0';
|
||||
static const char MJAllowedCodingPropertyNamesKey = '\0';
|
||||
static const char MJIgnoredCodingPropertyNamesKey = '\0';
|
||||
|
||||
@implementation NSObject (MJClass)
|
||||
|
||||
+ (NSMutableDictionary *)mj_classDictForKey:(const void *)key
|
||||
{
|
||||
static NSMutableDictionary *allowedPropertyNamesDict;
|
||||
static NSMutableDictionary *ignoredPropertyNamesDict;
|
||||
static NSMutableDictionary *allowedCodingPropertyNamesDict;
|
||||
static NSMutableDictionary *ignoredCodingPropertyNamesDict;
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
allowedPropertyNamesDict = [NSMutableDictionary dictionary];
|
||||
ignoredPropertyNamesDict = [NSMutableDictionary dictionary];
|
||||
allowedCodingPropertyNamesDict = [NSMutableDictionary dictionary];
|
||||
ignoredCodingPropertyNamesDict = [NSMutableDictionary dictionary];
|
||||
});
|
||||
|
||||
if (key == &MJAllowedPropertyNamesKey) return allowedPropertyNamesDict;
|
||||
if (key == &MJIgnoredPropertyNamesKey) return ignoredPropertyNamesDict;
|
||||
if (key == &MJAllowedCodingPropertyNamesKey) return allowedCodingPropertyNamesDict;
|
||||
if (key == &MJIgnoredCodingPropertyNamesKey) return ignoredCodingPropertyNamesDict;
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (void)mj_enumerateClasses:(MJClassesEnumeration)enumeration
|
||||
{
|
||||
// 1.没有block就直接返回
|
||||
if (enumeration == nil) return;
|
||||
|
||||
// 2.停止遍历的标记
|
||||
BOOL stop = NO;
|
||||
|
||||
// 3.当前正在遍历的类
|
||||
Class c = self;
|
||||
|
||||
// 4.开始遍历每一个类
|
||||
while (c && !stop) {
|
||||
// 4.1.执行操作
|
||||
enumeration(c, &stop);
|
||||
|
||||
// 4.2.获得父类
|
||||
c = class_getSuperclass(c);
|
||||
|
||||
if ([MJFoundation isClassFromFoundation:c]) break;
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)mj_enumerateAllClasses:(MJClassesEnumeration)enumeration
|
||||
{
|
||||
// 1.没有block就直接返回
|
||||
if (enumeration == nil) return;
|
||||
|
||||
// 2.停止遍历的标记
|
||||
BOOL stop = NO;
|
||||
|
||||
// 3.当前正在遍历的类
|
||||
Class c = self;
|
||||
|
||||
// 4.开始遍历每一个类
|
||||
while (c && !stop) {
|
||||
// 4.1.执行操作
|
||||
enumeration(c, &stop);
|
||||
|
||||
// 4.2.获得父类
|
||||
c = class_getSuperclass(c);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 属性黑名单配置
|
||||
+ (void)mj_setupIgnoredPropertyNames:(MJIgnoredPropertyNames)ignoredPropertyNames
|
||||
{
|
||||
[self mj_setupBlockReturnValue:ignoredPropertyNames key:&MJIgnoredPropertyNamesKey];
|
||||
}
|
||||
|
||||
+ (NSMutableArray *)mj_totalIgnoredPropertyNames
|
||||
{
|
||||
return [self mj_totalObjectsWithSelector:@selector(mj_ignoredPropertyNames) key:&MJIgnoredPropertyNamesKey];
|
||||
}
|
||||
|
||||
#pragma mark - 归档属性黑名单配置
|
||||
+ (void)mj_setupIgnoredCodingPropertyNames:(MJIgnoredCodingPropertyNames)ignoredCodingPropertyNames
|
||||
{
|
||||
[self mj_setupBlockReturnValue:ignoredCodingPropertyNames key:&MJIgnoredCodingPropertyNamesKey];
|
||||
}
|
||||
|
||||
+ (NSMutableArray *)mj_totalIgnoredCodingPropertyNames
|
||||
{
|
||||
return [self mj_totalObjectsWithSelector:@selector(mj_ignoredCodingPropertyNames) key:&MJIgnoredCodingPropertyNamesKey];
|
||||
}
|
||||
|
||||
#pragma mark - 属性白名单配置
|
||||
+ (void)mj_setupAllowedPropertyNames:(MJAllowedPropertyNames)allowedPropertyNames;
|
||||
{
|
||||
[self mj_setupBlockReturnValue:allowedPropertyNames key:&MJAllowedPropertyNamesKey];
|
||||
}
|
||||
|
||||
+ (NSMutableArray *)mj_totalAllowedPropertyNames
|
||||
{
|
||||
return [self mj_totalObjectsWithSelector:@selector(mj_allowedPropertyNames) key:&MJAllowedPropertyNamesKey];
|
||||
}
|
||||
|
||||
#pragma mark - 归档属性白名单配置
|
||||
+ (void)mj_setupAllowedCodingPropertyNames:(MJAllowedCodingPropertyNames)allowedCodingPropertyNames
|
||||
{
|
||||
[self mj_setupBlockReturnValue:allowedCodingPropertyNames key:&MJAllowedCodingPropertyNamesKey];
|
||||
}
|
||||
|
||||
+ (NSMutableArray *)mj_totalAllowedCodingPropertyNames
|
||||
{
|
||||
return [self mj_totalObjectsWithSelector:@selector(mj_allowedCodingPropertyNames) key:&MJAllowedCodingPropertyNamesKey];
|
||||
}
|
||||
|
||||
#pragma mark - block和方法处理:存储block的返回值
|
||||
+ (void)mj_setupBlockReturnValue:(id (^)(void))block key:(const char *)key {
|
||||
MJExtensionSemaphoreCreate
|
||||
MJ_LOCK(mje_signalSemaphore);
|
||||
if (block) {
|
||||
objc_setAssociatedObject(self, key, block(), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
} else {
|
||||
objc_setAssociatedObject(self, key, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
// 清空数据
|
||||
[[self mj_classDictForKey:key] removeAllObjects];
|
||||
MJ_UNLOCK(mje_signalSemaphore);
|
||||
}
|
||||
|
||||
+ (NSMutableArray *)mj_totalObjectsWithSelector:(SEL)selector key:(const char *)key
|
||||
{
|
||||
MJExtensionSemaphoreCreate
|
||||
MJ_LOCK(mje_signalSemaphore);
|
||||
NSMutableArray *array = [self mj_classDictForKey:key][NSStringFromClass(self)];
|
||||
if (array == nil) {
|
||||
// 创建、存储
|
||||
[self mj_classDictForKey:key][NSStringFromClass(self)] = array = [NSMutableArray array];
|
||||
|
||||
if ([self respondsToSelector:selector]) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
NSArray *subArray = [self performSelector:selector];
|
||||
#pragma clang diagnostic pop
|
||||
if (subArray) {
|
||||
[array addObjectsFromArray:subArray];
|
||||
}
|
||||
}
|
||||
|
||||
[self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
|
||||
NSArray *subArray = objc_getAssociatedObject(c, key);
|
||||
[array addObjectsFromArray:subArray];
|
||||
}];
|
||||
}
|
||||
MJ_UNLOCK(mje_signalSemaphore);
|
||||
return array;
|
||||
}
|
||||
@end
|
||||
66
Pods/MJExtension/MJExtension/NSObject+MJCoding.h
generated
Executable file
66
Pods/MJExtension/MJExtension/NSObject+MJCoding.h
generated
Executable file
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// NSObject+MJCoding.h
|
||||
// MJExtension
|
||||
//
|
||||
// Created by mj on 14-1-15.
|
||||
// Copyright (c) 2014年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MJExtensionConst.h"
|
||||
|
||||
/**
|
||||
* Codeing协议
|
||||
*/
|
||||
@protocol MJCoding <NSObject>
|
||||
@optional
|
||||
/**
|
||||
* 这个数组中的属性名才会进行归档
|
||||
*/
|
||||
+ (NSArray *)mj_allowedCodingPropertyNames;
|
||||
/**
|
||||
* 这个数组中的属性名将会被忽略:不进行归档
|
||||
*/
|
||||
+ (NSArray *)mj_ignoredCodingPropertyNames;
|
||||
@end
|
||||
|
||||
@interface NSObject (MJCoding) <MJCoding>
|
||||
/**
|
||||
* 解码(从文件中解析对象)
|
||||
*/
|
||||
- (void)mj_decode:(NSCoder *)decoder;
|
||||
/**
|
||||
* 编码(将对象写入文件中)
|
||||
*/
|
||||
- (void)mj_encode:(NSCoder *)encoder;
|
||||
@end
|
||||
|
||||
/**
|
||||
归档的实现
|
||||
*/
|
||||
#define MJCodingImplementation \
|
||||
- (id)initWithCoder:(NSCoder *)decoder \
|
||||
{ \
|
||||
if (self = [super init]) { \
|
||||
[self mj_decode:decoder]; \
|
||||
} \
|
||||
return self; \
|
||||
} \
|
||||
\
|
||||
- (void)encodeWithCoder:(NSCoder *)encoder \
|
||||
{ \
|
||||
[self mj_encode:encoder]; \
|
||||
}\
|
||||
|
||||
#define MJExtensionCodingImplementation MJCodingImplementation
|
||||
|
||||
#define MJSecureCodingImplementation(CLASS, FLAG) \
|
||||
@interface CLASS (MJSecureCoding) <NSSecureCoding> \
|
||||
@end \
|
||||
@implementation CLASS (MJSecureCoding) \
|
||||
MJCodingImplementation \
|
||||
+ (BOOL)supportsSecureCoding { \
|
||||
return FLAG; \
|
||||
} \
|
||||
@end \
|
||||
|
||||
59
Pods/MJExtension/MJExtension/NSObject+MJCoding.m
generated
Executable file
59
Pods/MJExtension/MJExtension/NSObject+MJCoding.m
generated
Executable file
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// NSObject+MJCoding.m
|
||||
// MJExtension
|
||||
//
|
||||
// Created by mj on 14-1-15.
|
||||
// Copyright (c) 2014年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSObject+MJCoding.h"
|
||||
#import "NSObject+MJClass.h"
|
||||
#import "NSObject+MJProperty.h"
|
||||
#import "MJProperty.h"
|
||||
|
||||
@implementation NSObject (MJCoding)
|
||||
|
||||
- (void)mj_encode:(NSCoder *)encoder
|
||||
{
|
||||
Class clazz = [self class];
|
||||
|
||||
NSArray *allowedCodingPropertyNames = [clazz mj_totalAllowedCodingPropertyNames];
|
||||
NSArray *ignoredCodingPropertyNames = [clazz mj_totalIgnoredCodingPropertyNames];
|
||||
|
||||
[clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) {
|
||||
// 检测是否被忽略
|
||||
if (allowedCodingPropertyNames.count && ![allowedCodingPropertyNames containsObject:property.name]) return;
|
||||
if ([ignoredCodingPropertyNames containsObject:property.name]) return;
|
||||
|
||||
id value = [property valueForObject:self];
|
||||
if (value == nil) return;
|
||||
[encoder encodeObject:value forKey:property.name];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)mj_decode:(NSCoder *)decoder
|
||||
{
|
||||
Class clazz = [self class];
|
||||
|
||||
NSArray *allowedCodingPropertyNames = [clazz mj_totalAllowedCodingPropertyNames];
|
||||
NSArray *ignoredCodingPropertyNames = [clazz mj_totalIgnoredCodingPropertyNames];
|
||||
|
||||
[clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) {
|
||||
// 检测是否被忽略
|
||||
if (allowedCodingPropertyNames.count && ![allowedCodingPropertyNames containsObject:property.name]) return;
|
||||
if ([ignoredCodingPropertyNames containsObject:property.name]) return;
|
||||
|
||||
// fixed `-[NSKeyedUnarchiver validateAllowedClass:forKey:] allowed unarchiving safe plist type ''NSNumber'(This will be disallowed in the future.)` warning.
|
||||
Class genericClass = [property objectClassInArrayForClass:property.srcClass];
|
||||
// If genericClass exists, property.type.typeClass would be a collection type(Array, Set, Dictionary). This scenario([obj, nil, obj, nil]) would not happened.
|
||||
NSSet *classes = [NSSet setWithObjects:NSNumber.class,
|
||||
property.type.typeClass, genericClass, nil];
|
||||
id value = [decoder decodeObjectOfClasses:classes forKey:property.name];
|
||||
if (value == nil) { // 兼容以前的MJExtension版本
|
||||
value = [decoder decodeObjectForKey:[@"_" stringByAppendingString:property.name]];
|
||||
}
|
||||
if (value == nil) return;
|
||||
[property setValue:value forObject:self];
|
||||
}];
|
||||
}
|
||||
@end
|
||||
194
Pods/MJExtension/MJExtension/NSObject+MJKeyValue.h
generated
Executable file
194
Pods/MJExtension/MJExtension/NSObject+MJKeyValue.h
generated
Executable file
@@ -0,0 +1,194 @@
|
||||
//
|
||||
// NSObject+MJKeyValue.h
|
||||
// MJExtension
|
||||
//
|
||||
// Created by mj on 13-8-24.
|
||||
// Copyright (c) 2013年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MJExtensionConst.h"
|
||||
#import <CoreData/CoreData.h>
|
||||
#import "MJProperty.h"
|
||||
|
||||
/**
|
||||
* KeyValue协议
|
||||
*/
|
||||
@protocol MJKeyValue <NSObject>
|
||||
@optional
|
||||
/**
|
||||
* 只有这个数组中的属性名才允许进行字典和模型的转换
|
||||
*/
|
||||
+ (NSArray *)mj_allowedPropertyNames;
|
||||
|
||||
/**
|
||||
* 这个数组中的属性名将会被忽略:不进行字典和模型的转换
|
||||
*/
|
||||
+ (NSArray *)mj_ignoredPropertyNames;
|
||||
|
||||
/**
|
||||
* 将属性名换为其他key去字典中取值
|
||||
*
|
||||
* @return 字典中的key是属性名,value是从字典中取值用的key
|
||||
*/
|
||||
+ (NSDictionary *)mj_replacedKeyFromPropertyName;
|
||||
|
||||
/**
|
||||
* 将属性名换为其他key去字典中取值
|
||||
*
|
||||
* @return 从字典中取值用的key
|
||||
*/
|
||||
+ (id)mj_replacedKeyFromPropertyName121:(NSString *)propertyName;
|
||||
|
||||
/**
|
||||
* 数组中需要转换的模型类
|
||||
*
|
||||
* @return 字典中的key是数组属性名,value是数组中存放模型的Class(Class类型或者NSString类型)
|
||||
*/
|
||||
+ (NSDictionary *)mj_objectClassInArray;
|
||||
|
||||
|
||||
/** 特殊地区在字符串格式化数字时使用 */
|
||||
+ (NSLocale *)mj_numberLocale;
|
||||
|
||||
/**
|
||||
* 旧值换新值,用于过滤字典中的值
|
||||
*
|
||||
* @param oldValue 旧值
|
||||
*
|
||||
* @return 新值
|
||||
*/
|
||||
- (id)mj_newValueFromOldValue:(id)oldValue property:(MJProperty *)property;
|
||||
|
||||
/**
|
||||
* 当字典转模型完毕时调用
|
||||
*/
|
||||
- (void)mj_keyValuesDidFinishConvertingToObject MJExtensionDeprecated("请使用`mj_didConvertToObjectWithKeyValues:`替代");
|
||||
- (void)mj_keyValuesDidFinishConvertingToObject:(NSDictionary *)keyValues MJExtensionDeprecated("请使用`mj_didConvertToObjectWithKeyValues:`替代");
|
||||
- (void)mj_didConvertToObjectWithKeyValues:(NSDictionary *)keyValues;
|
||||
|
||||
/**
|
||||
* 当模型转字典完毕时调用
|
||||
*/
|
||||
- (void)mj_objectDidFinishConvertingToKeyValues MJExtensionDeprecated("请使用`mj_objectDidConvertToKeyValues:`替代");
|
||||
- (void)mj_objectDidConvertToKeyValues:(NSMutableDictionary *)keyValues;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSObject (MJKeyValue) <MJKeyValue>
|
||||
#pragma mark - 类方法
|
||||
/**
|
||||
* 字典转模型过程中遇到的错误
|
||||
*/
|
||||
+ (NSError *)mj_error;
|
||||
|
||||
/**
|
||||
* 模型转字典时,字典的key是否参考replacedKeyFromPropertyName等方法(父类设置了,子类也会继承下来)
|
||||
*/
|
||||
+ (void)mj_referenceReplacedKeyWhenCreatingKeyValues:(BOOL)reference;
|
||||
|
||||
#pragma mark - 对象方法
|
||||
/**
|
||||
* 将字典的键值对转成模型属性
|
||||
* @param keyValues 字典(可以是NSDictionary、NSData、NSString)
|
||||
*/
|
||||
- (instancetype)mj_setKeyValues:(id)keyValues;
|
||||
|
||||
/**
|
||||
* 将字典的键值对转成模型属性
|
||||
* @param keyValues 字典(可以是NSDictionary、NSData、NSString)
|
||||
* @param context CoreData上下文
|
||||
*/
|
||||
- (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context;
|
||||
|
||||
/**
|
||||
* 将模型转成字典
|
||||
* @return 字典
|
||||
*/
|
||||
- (NSMutableDictionary *)mj_keyValues;
|
||||
- (NSMutableDictionary *)mj_keyValuesWithKeys:(NSArray *)keys;
|
||||
- (NSMutableDictionary *)mj_keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys;
|
||||
|
||||
/**
|
||||
* 通过模型数组来创建一个字典数组
|
||||
* @param objectArray 模型数组
|
||||
* @return 字典数组
|
||||
*/
|
||||
+ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray;
|
||||
+ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys;
|
||||
+ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys;
|
||||
|
||||
#pragma mark - 字典转模型
|
||||
/**
|
||||
* 通过字典来创建一个模型
|
||||
* @param keyValues 字典(可以是NSDictionary、NSData、NSString)
|
||||
* @return 新建的对象
|
||||
*/
|
||||
+ (instancetype)mj_objectWithKeyValues:(id)keyValues;
|
||||
|
||||
/**
|
||||
* 通过字典来创建一个CoreData模型
|
||||
* @param keyValues 字典(可以是NSDictionary、NSData、NSString)
|
||||
* @param context CoreData上下文
|
||||
* @return 新建的对象
|
||||
*/
|
||||
+ (instancetype)mj_objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context;
|
||||
|
||||
/**
|
||||
* 通过plist来创建一个模型
|
||||
* @param filename 文件名(仅限于mainBundle中的文件)
|
||||
* @return 新建的对象
|
||||
*/
|
||||
+ (instancetype)mj_objectWithFilename:(NSString *)filename;
|
||||
|
||||
/**
|
||||
* 通过plist来创建一个模型
|
||||
* @param file 文件全路径
|
||||
* @return 新建的对象
|
||||
*/
|
||||
+ (instancetype)mj_objectWithFile:(NSString *)file;
|
||||
|
||||
#pragma mark - 字典数组转模型数组
|
||||
/**
|
||||
* 通过字典数组来创建一个模型数组
|
||||
* @param keyValuesArray 字典数组(可以是NSDictionary、NSData、NSString)
|
||||
* @return 模型数组
|
||||
*/
|
||||
+ (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(id)keyValuesArray;
|
||||
|
||||
/**
|
||||
* 通过字典数组来创建一个模型数组
|
||||
* @param keyValuesArray 字典数组(可以是NSDictionary、NSData、NSString)
|
||||
* @param context CoreData上下文
|
||||
* @return 模型数组
|
||||
*/
|
||||
+ (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context;
|
||||
|
||||
/**
|
||||
* 通过plist来创建一个模型数组
|
||||
* @param filename 文件名(仅限于mainBundle中的文件)
|
||||
* @return 模型数组
|
||||
*/
|
||||
+ (NSMutableArray *)mj_objectArrayWithFilename:(NSString *)filename;
|
||||
|
||||
/**
|
||||
* 通过plist来创建一个模型数组
|
||||
* @param file 文件全路径
|
||||
* @return 模型数组
|
||||
*/
|
||||
+ (NSMutableArray *)mj_objectArrayWithFile:(NSString *)file;
|
||||
|
||||
#pragma mark - 转换为JSON
|
||||
/**
|
||||
* 转换为JSON Data
|
||||
*/
|
||||
- (NSData *)mj_JSONData;
|
||||
/**
|
||||
* 转换为字典或者数组
|
||||
*/
|
||||
- (id)mj_JSONObject;
|
||||
/**
|
||||
* 转换为JSON 字符串
|
||||
*/
|
||||
- (NSString *)mj_JSONString;
|
||||
@end
|
||||
524
Pods/MJExtension/MJExtension/NSObject+MJKeyValue.m
generated
Executable file
524
Pods/MJExtension/MJExtension/NSObject+MJKeyValue.m
generated
Executable file
@@ -0,0 +1,524 @@
|
||||
//
|
||||
// NSObject+MJKeyValue.m
|
||||
// MJExtension
|
||||
//
|
||||
// Created by mj on 13-8-24.
|
||||
// Copyright (c) 2013年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSObject+MJKeyValue.h"
|
||||
#import "NSObject+MJProperty.h"
|
||||
#import "NSString+MJExtension.h"
|
||||
#import "MJProperty.h"
|
||||
#import "MJPropertyType.h"
|
||||
#import "MJExtensionConst.h"
|
||||
#import "MJFoundation.h"
|
||||
#import "NSString+MJExtension.h"
|
||||
#import "NSObject+MJClass.h"
|
||||
|
||||
@implementation NSDecimalNumber(MJKeyValue)
|
||||
|
||||
- (id)mj_standardValueWithTypeCode:(NSString *)typeCode {
|
||||
// 由于这里涉及到编译器问题, 暂时保留 Long, 实际上在 64 位系统上, 这 2 个精度范围相同,
|
||||
// 32 位略有不同, 其余都可使用 Double 进行强转不丢失精度
|
||||
if ([typeCode isEqualToString:MJPropertyTypeLongLong]) {
|
||||
return @(self.longLongValue);
|
||||
} else if ([typeCode isEqualToString:MJPropertyTypeLongLong.uppercaseString]) {
|
||||
return @(self.unsignedLongLongValue);
|
||||
} else if ([typeCode isEqualToString:MJPropertyTypeLong]) {
|
||||
return @(self.longValue);
|
||||
} else if ([typeCode isEqualToString:MJPropertyTypeLong.uppercaseString]) {
|
||||
return @(self.unsignedLongValue);
|
||||
} else {
|
||||
return @(self.doubleValue);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSObject (MJKeyValue)
|
||||
|
||||
#pragma mark - 错误
|
||||
static const char MJErrorKey = '\0';
|
||||
+ (NSError *)mj_error
|
||||
{
|
||||
return objc_getAssociatedObject(self, &MJErrorKey);
|
||||
}
|
||||
|
||||
+ (void)setMj_error:(NSError *)error
|
||||
{
|
||||
objc_setAssociatedObject(self, &MJErrorKey, error, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
#pragma mark - 模型 -> 字典时的参考
|
||||
/** 模型转字典时,字典的key是否参考replacedKeyFromPropertyName等方法(父类设置了,子类也会继承下来) */
|
||||
static const char MJReferenceReplacedKeyWhenCreatingKeyValuesKey = '\0';
|
||||
|
||||
+ (void)mj_referenceReplacedKeyWhenCreatingKeyValues:(BOOL)reference
|
||||
{
|
||||
objc_setAssociatedObject(self, &MJReferenceReplacedKeyWhenCreatingKeyValuesKey, @(reference), OBJC_ASSOCIATION_ASSIGN);
|
||||
}
|
||||
|
||||
+ (BOOL)mj_isReferenceReplacedKeyWhenCreatingKeyValues
|
||||
{
|
||||
__block id value = objc_getAssociatedObject(self, &MJReferenceReplacedKeyWhenCreatingKeyValuesKey);
|
||||
if (!value) {
|
||||
[self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
|
||||
value = objc_getAssociatedObject(c, &MJReferenceReplacedKeyWhenCreatingKeyValuesKey);
|
||||
|
||||
if (value) *stop = YES;
|
||||
}];
|
||||
}
|
||||
return [value boolValue];
|
||||
}
|
||||
|
||||
#pragma mark - --常用的对象--
|
||||
+ (void)load
|
||||
{
|
||||
// 默认设置
|
||||
[self mj_referenceReplacedKeyWhenCreatingKeyValues:YES];
|
||||
}
|
||||
|
||||
#pragma mark - --公共方法--
|
||||
#pragma mark - 字典 -> 模型
|
||||
- (instancetype)mj_setKeyValues:(id)keyValues
|
||||
{
|
||||
return [self mj_setKeyValues:keyValues context:nil];
|
||||
}
|
||||
|
||||
/**
|
||||
核心代码:
|
||||
*/
|
||||
- (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
|
||||
{
|
||||
// 获得JSON对象
|
||||
keyValues = [keyValues mj_JSONObject];
|
||||
|
||||
MJExtensionAssertError([keyValues isKindOfClass:[NSDictionary class]], self, [self class], @"keyValues参数不是一个字典");
|
||||
|
||||
Class clazz = [self class];
|
||||
NSArray *allowedPropertyNames = [clazz mj_totalAllowedPropertyNames];
|
||||
NSArray *ignoredPropertyNames = [clazz mj_totalIgnoredPropertyNames];
|
||||
|
||||
NSLocale *numberLocale = nil;
|
||||
if ([self.class respondsToSelector:@selector(mj_numberLocale)]) {
|
||||
numberLocale = self.class.mj_numberLocale;
|
||||
}
|
||||
|
||||
//通过封装的方法回调一个通过运行时编写的,用于返回属性列表的方法。
|
||||
[clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) {
|
||||
@try {
|
||||
// 0.检测是否被忽略
|
||||
if (allowedPropertyNames.count && ![allowedPropertyNames containsObject:property.name]) return;
|
||||
if ([ignoredPropertyNames containsObject:property.name]) return;
|
||||
|
||||
// 1.取出属性值
|
||||
id value;
|
||||
NSArray *propertyKeyses = [property propertyKeysForClass:clazz];
|
||||
for (NSArray *propertyKeys in propertyKeyses) {
|
||||
value = keyValues;
|
||||
for (MJPropertyKey *propertyKey in propertyKeys) {
|
||||
value = [propertyKey valueInObject:value];
|
||||
}
|
||||
if (value) break;
|
||||
}
|
||||
|
||||
// 值的过滤
|
||||
id newValue = [clazz mj_getNewValueFromObject:self oldValue:value property:property];
|
||||
if (newValue != value) { // 有过滤后的新值
|
||||
[property setValue:newValue forObject:self];
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果没有值,就直接返回
|
||||
if (!value || value == [NSNull null]) return;
|
||||
|
||||
// 2.复杂处理
|
||||
MJPropertyType *type = property.type;
|
||||
Class propertyClass = type.typeClass;
|
||||
Class objectClass = [property objectClassInArrayForClass:[self class]];
|
||||
|
||||
// 不可变 -> 可变处理
|
||||
if (propertyClass == [NSMutableArray class] && [value isKindOfClass:[NSArray class]]) {
|
||||
value = [NSMutableArray arrayWithArray:value];
|
||||
} else if (propertyClass == [NSMutableDictionary class] && [value isKindOfClass:[NSDictionary class]]) {
|
||||
value = [NSMutableDictionary dictionaryWithDictionary:value];
|
||||
} else if (propertyClass == [NSMutableString class] && [value isKindOfClass:[NSString class]]) {
|
||||
value = [NSMutableString stringWithString:value];
|
||||
} else if (propertyClass == [NSMutableData class] && [value isKindOfClass:[NSData class]]) {
|
||||
value = [NSMutableData dataWithData:value];
|
||||
}
|
||||
|
||||
if (!type.isFromFoundation && propertyClass) { // 模型属性
|
||||
value = [propertyClass mj_objectWithKeyValues:value context:context];
|
||||
} else if (objectClass) {
|
||||
if (objectClass == [NSURL class] && [value isKindOfClass:[NSArray class]]) {
|
||||
// string array -> url array
|
||||
NSMutableArray *urlArray = [NSMutableArray array];
|
||||
for (NSString *string in value) {
|
||||
if (![string isKindOfClass:[NSString class]]) continue;
|
||||
[urlArray addObject:string.mj_url];
|
||||
}
|
||||
value = urlArray;
|
||||
} else { // 字典数组-->模型数组
|
||||
value = [objectClass mj_objectArrayWithKeyValuesArray:value context:context];
|
||||
}
|
||||
} else if (propertyClass == [NSString class]) {
|
||||
if ([value isKindOfClass:[NSNumber class]]) {
|
||||
// NSNumber -> NSString
|
||||
value = [value description];
|
||||
} else if ([value isKindOfClass:[NSURL class]]) {
|
||||
// NSURL -> NSString
|
||||
value = [value absoluteString];
|
||||
}
|
||||
} else if ([value isKindOfClass:[NSString class]]) {
|
||||
if (propertyClass == [NSURL class]) {
|
||||
// NSString -> NSURL
|
||||
// 字符串转码
|
||||
value = [value mj_url];
|
||||
} else if (type.isNumberType) {
|
||||
NSString *oldValue = value;
|
||||
|
||||
// NSString -> NSDecimalNumber, 使用 DecimalNumber 来转换数字, 避免丢失精度以及溢出
|
||||
NSDecimalNumber *decimalValue = [NSDecimalNumber decimalNumberWithString:oldValue
|
||||
locale:numberLocale];
|
||||
|
||||
// 检查特殊情况
|
||||
if (decimalValue == NSDecimalNumber.notANumber) {
|
||||
value = @(0);
|
||||
}else if (propertyClass != [NSDecimalNumber class]) {
|
||||
value = [decimalValue mj_standardValueWithTypeCode:type.code];
|
||||
} else {
|
||||
value = decimalValue;
|
||||
}
|
||||
|
||||
// 如果是BOOL
|
||||
if (type.isBoolType) {
|
||||
// 字符串转BOOL(字符串没有charValue方法)
|
||||
// 系统会调用字符串的charValue转为BOOL类型
|
||||
NSString *lower = [oldValue lowercaseString];
|
||||
if ([lower isEqualToString:@"yes"] || [lower isEqualToString:@"true"]) {
|
||||
value = @YES;
|
||||
} else if ([lower isEqualToString:@"no"] || [lower isEqualToString:@"false"]) {
|
||||
value = @NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ([value isKindOfClass:[NSNumber class]] && propertyClass == [NSDecimalNumber class]){
|
||||
// 过滤 NSDecimalNumber类型
|
||||
if (![value isKindOfClass:[NSDecimalNumber class]]) {
|
||||
value = [NSDecimalNumber decimalNumberWithDecimal:[((NSNumber *)value) decimalValue]];
|
||||
}
|
||||
}
|
||||
|
||||
// 经过转换后, 最终检查 value 与 property 是否匹配
|
||||
if (propertyClass && ![value isKindOfClass:propertyClass]) {
|
||||
value = nil;
|
||||
}
|
||||
|
||||
// 3.赋值
|
||||
[property setValue:value forObject:self];
|
||||
} @catch (NSException *exception) {
|
||||
MJExtensionBuildError([self class], exception.reason);
|
||||
MJExtensionLog(@"%@", exception);
|
||||
#ifdef DEBUG
|
||||
[exception raise];
|
||||
#endif
|
||||
}
|
||||
}];
|
||||
|
||||
// 转换完毕
|
||||
if ([self respondsToSelector:@selector(mj_didConvertToObjectWithKeyValues:)]) {
|
||||
[self mj_didConvertToObjectWithKeyValues:keyValues];
|
||||
}
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
|
||||
if ([self respondsToSelector:@selector(mj_keyValuesDidFinishConvertingToObject)]) {
|
||||
[self mj_keyValuesDidFinishConvertingToObject];
|
||||
}
|
||||
if ([self respondsToSelector:@selector(mj_keyValuesDidFinishConvertingToObject:)]) {
|
||||
[self mj_keyValuesDidFinishConvertingToObject:keyValues];
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)mj_objectWithKeyValues:(id)keyValues
|
||||
{
|
||||
return [self mj_objectWithKeyValues:keyValues context:nil];
|
||||
}
|
||||
|
||||
+ (instancetype)mj_objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
|
||||
{
|
||||
// 获得JSON对象
|
||||
keyValues = [keyValues mj_JSONObject];
|
||||
MJExtensionAssertError([keyValues isKindOfClass:[NSDictionary class]], nil, [self class], @"keyValues参数不是一个字典");
|
||||
|
||||
if ([self isSubclassOfClass:[NSManagedObject class]] && context) {
|
||||
NSString *entityName = [(NSManagedObject *)self entity].name;
|
||||
return [[NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context] mj_setKeyValues:keyValues context:context];
|
||||
}
|
||||
return [[[self alloc] init] mj_setKeyValues:keyValues];
|
||||
}
|
||||
|
||||
+ (instancetype)mj_objectWithFilename:(NSString *)filename
|
||||
{
|
||||
MJExtensionAssertError(filename != nil, nil, [self class], @"filename参数为nil");
|
||||
|
||||
return [self mj_objectWithFile:[[NSBundle mainBundle] pathForResource:filename ofType:nil]];
|
||||
}
|
||||
|
||||
+ (instancetype)mj_objectWithFile:(NSString *)file
|
||||
{
|
||||
MJExtensionAssertError(file != nil, nil, [self class], @"file参数为nil");
|
||||
|
||||
return [self mj_objectWithKeyValues:[NSDictionary dictionaryWithContentsOfFile:file]];
|
||||
}
|
||||
|
||||
#pragma mark - 字典数组 -> 模型数组
|
||||
+ (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(NSArray *)keyValuesArray
|
||||
{
|
||||
return [self mj_objectArrayWithKeyValuesArray:keyValuesArray context:nil];
|
||||
}
|
||||
|
||||
+ (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context
|
||||
{
|
||||
// 如果是JSON字符串
|
||||
keyValuesArray = [keyValuesArray mj_JSONObject];
|
||||
|
||||
// 1.判断真实性
|
||||
MJExtensionAssertError([keyValuesArray isKindOfClass:[NSArray class]], nil, [self class], @"keyValuesArray参数不是一个数组");
|
||||
|
||||
// 如果数组里面放的是NSString、NSNumber等数据
|
||||
if ([MJFoundation isClassFromFoundation:self]) return [NSMutableArray arrayWithArray:keyValuesArray];
|
||||
|
||||
|
||||
// 2.创建数组
|
||||
NSMutableArray *modelArray = [NSMutableArray array];
|
||||
|
||||
// 3.遍历
|
||||
for (NSDictionary *keyValues in keyValuesArray) {
|
||||
if ([keyValues isKindOfClass:[NSArray class]]){
|
||||
[modelArray addObject:[self mj_objectArrayWithKeyValuesArray:keyValues context:context]];
|
||||
} else {
|
||||
id model = [self mj_objectWithKeyValues:keyValues context:context];
|
||||
if (model) [modelArray addObject:model];
|
||||
}
|
||||
}
|
||||
|
||||
return modelArray;
|
||||
}
|
||||
|
||||
+ (NSMutableArray *)mj_objectArrayWithFilename:(NSString *)filename
|
||||
{
|
||||
MJExtensionAssertError(filename != nil, nil, [self class], @"filename参数为nil");
|
||||
|
||||
return [self mj_objectArrayWithFile:[[NSBundle mainBundle] pathForResource:filename ofType:nil]];
|
||||
}
|
||||
|
||||
+ (NSMutableArray *)mj_objectArrayWithFile:(NSString *)file
|
||||
{
|
||||
MJExtensionAssertError(file != nil, nil, [self class], @"file参数为nil");
|
||||
|
||||
return [self mj_objectArrayWithKeyValuesArray:[NSArray arrayWithContentsOfFile:file]];
|
||||
}
|
||||
|
||||
#pragma mark - 模型 -> 字典
|
||||
- (NSMutableDictionary *)mj_keyValues
|
||||
{
|
||||
return [self mj_keyValuesWithKeys:nil ignoredKeys:nil];
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)mj_keyValuesWithKeys:(NSArray *)keys
|
||||
{
|
||||
return [self mj_keyValuesWithKeys:keys ignoredKeys:nil];
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)mj_keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys
|
||||
{
|
||||
return [self mj_keyValuesWithKeys:nil ignoredKeys:ignoredKeys];
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)mj_keyValuesWithKeys:(NSArray *)keys ignoredKeys:(NSArray *)ignoredKeys
|
||||
{
|
||||
// 如果自己不是模型类, 那就返回自己
|
||||
// 模型类过滤掉 NSNull
|
||||
// 唯一一个不返回自己的
|
||||
if ([self isMemberOfClass:NSNull.class]) { return nil; }
|
||||
// 这里虽然返回了自己, 但是其实是有报错信息的.
|
||||
// TODO: 报错机制不好, 需要重做
|
||||
MJExtensionAssertError(![MJFoundation isClassFromFoundation:[self class]], (NSMutableDictionary *)self, [self class], @"不是自定义的模型类")
|
||||
|
||||
id keyValues = [NSMutableDictionary dictionary];
|
||||
|
||||
Class clazz = [self class];
|
||||
NSArray *allowedPropertyNames = [clazz mj_totalAllowedPropertyNames];
|
||||
NSArray *ignoredPropertyNames = [clazz mj_totalIgnoredPropertyNames];
|
||||
|
||||
[clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) {
|
||||
@try {
|
||||
// 0.检测是否被忽略
|
||||
if (allowedPropertyNames.count && ![allowedPropertyNames containsObject:property.name]) return;
|
||||
if ([ignoredPropertyNames containsObject:property.name]) return;
|
||||
if (keys.count && ![keys containsObject:property.name]) return;
|
||||
if ([ignoredKeys containsObject:property.name]) return;
|
||||
|
||||
// 1.取出属性值
|
||||
id value = [property valueForObject:self];
|
||||
if (!value) return;
|
||||
|
||||
// 2.如果是模型属性
|
||||
MJPropertyType *type = property.type;
|
||||
Class propertyClass = type.typeClass;
|
||||
if (!type.isFromFoundation && propertyClass) {
|
||||
value = [value mj_keyValues];
|
||||
} else if ([value isKindOfClass:[NSArray class]]) {
|
||||
// 3.处理数组里面有模型的情况
|
||||
value = [NSObject mj_keyValuesArrayWithObjectArray:value];
|
||||
} else if (propertyClass == [NSURL class]) {
|
||||
value = [value absoluteString];
|
||||
}
|
||||
|
||||
// 4.赋值
|
||||
if ([clazz mj_isReferenceReplacedKeyWhenCreatingKeyValues]) {
|
||||
NSArray *propertyKeys = [[property propertyKeysForClass:clazz] firstObject];
|
||||
NSUInteger keyCount = propertyKeys.count;
|
||||
// 创建字典
|
||||
__block id innerContainer = keyValues;
|
||||
[propertyKeys enumerateObjectsUsingBlock:^(MJPropertyKey *propertyKey, NSUInteger idx, BOOL *stop) {
|
||||
// 下一个属性
|
||||
MJPropertyKey *nextPropertyKey = nil;
|
||||
if (idx != keyCount - 1) {
|
||||
nextPropertyKey = propertyKeys[idx + 1];
|
||||
}
|
||||
|
||||
if (nextPropertyKey) { // 不是最后一个key
|
||||
// 当前propertyKey对应的字典或者数组
|
||||
id tempInnerContainer = [propertyKey valueInObject:innerContainer];
|
||||
if (tempInnerContainer == nil || [tempInnerContainer isKindOfClass:[NSNull class]]) {
|
||||
if (nextPropertyKey.type == MJPropertyKeyTypeDictionary) {
|
||||
tempInnerContainer = [NSMutableDictionary dictionary];
|
||||
} else {
|
||||
tempInnerContainer = [NSMutableArray array];
|
||||
}
|
||||
if (propertyKey.type == MJPropertyKeyTypeDictionary) {
|
||||
innerContainer[propertyKey.name] = tempInnerContainer;
|
||||
} else {
|
||||
innerContainer[propertyKey.name.intValue] = tempInnerContainer;
|
||||
}
|
||||
}
|
||||
|
||||
if ([tempInnerContainer isKindOfClass:[NSMutableArray class]]) {
|
||||
NSMutableArray *tempInnerContainerArray = tempInnerContainer;
|
||||
int index = nextPropertyKey.name.intValue;
|
||||
while (tempInnerContainerArray.count < index + 1) {
|
||||
[tempInnerContainerArray addObject:[NSNull null]];
|
||||
}
|
||||
}
|
||||
|
||||
innerContainer = tempInnerContainer;
|
||||
} else { // 最后一个key
|
||||
if (propertyKey.type == MJPropertyKeyTypeDictionary) {
|
||||
innerContainer[propertyKey.name] = value;
|
||||
} else {
|
||||
innerContainer[propertyKey.name.intValue] = value;
|
||||
}
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
keyValues[property.name] = value;
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
MJExtensionBuildError([self class], exception.reason);
|
||||
MJExtensionLog(@"%@", exception);
|
||||
#ifdef DEBUG
|
||||
[exception raise];
|
||||
#endif
|
||||
}
|
||||
}];
|
||||
|
||||
// 转换完毕
|
||||
if ([self respondsToSelector:@selector(mj_objectDidConvertToKeyValues:)]) {
|
||||
[self mj_objectDidConvertToKeyValues:keyValues];
|
||||
}
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
|
||||
if ([self respondsToSelector:@selector(mj_objectDidFinishConvertingToKeyValues)]) {
|
||||
[self mj_objectDidFinishConvertingToKeyValues];
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
return keyValues;
|
||||
}
|
||||
#pragma mark - 模型数组 -> 字典数组
|
||||
+ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray
|
||||
{
|
||||
return [self mj_keyValuesArrayWithObjectArray:objectArray keys:nil ignoredKeys:nil];
|
||||
}
|
||||
|
||||
+ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys
|
||||
{
|
||||
return [self mj_keyValuesArrayWithObjectArray:objectArray keys:keys ignoredKeys:nil];
|
||||
}
|
||||
|
||||
+ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys
|
||||
{
|
||||
return [self mj_keyValuesArrayWithObjectArray:objectArray keys:nil ignoredKeys:ignoredKeys];
|
||||
}
|
||||
|
||||
+ (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys ignoredKeys:(NSArray *)ignoredKeys
|
||||
{
|
||||
// 0.判断真实性
|
||||
MJExtensionAssertError([objectArray isKindOfClass:[NSArray class]], nil, [self class], @"objectArray参数不是一个数组");
|
||||
|
||||
// 1.创建数组
|
||||
NSMutableArray *keyValuesArray = [NSMutableArray array];
|
||||
for (id object in objectArray) {
|
||||
if (keys) {
|
||||
id convertedObj = [object mj_keyValuesWithKeys:keys];
|
||||
if (!convertedObj) { continue; }
|
||||
[keyValuesArray addObject:convertedObj];
|
||||
} else {
|
||||
id convertedObj = [object mj_keyValuesWithIgnoredKeys:ignoredKeys];
|
||||
if (!convertedObj) { continue; }
|
||||
[keyValuesArray addObject:convertedObj];
|
||||
}
|
||||
}
|
||||
return keyValuesArray;
|
||||
}
|
||||
|
||||
#pragma mark - 转换为JSON
|
||||
- (NSData *)mj_JSONData
|
||||
{
|
||||
if ([self isKindOfClass:[NSString class]]) {
|
||||
return [((NSString *)self) dataUsingEncoding:NSUTF8StringEncoding];
|
||||
} else if ([self isKindOfClass:[NSData class]]) {
|
||||
return (NSData *)self;
|
||||
}
|
||||
|
||||
return [NSJSONSerialization dataWithJSONObject:[self mj_JSONObject] options:kNilOptions error:nil];
|
||||
}
|
||||
|
||||
- (id)mj_JSONObject
|
||||
{
|
||||
if ([self isKindOfClass:[NSString class]]) {
|
||||
return [NSJSONSerialization JSONObjectWithData:[((NSString *)self) dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
|
||||
} else if ([self isKindOfClass:[NSData class]]) {
|
||||
return [NSJSONSerialization JSONObjectWithData:(NSData *)self options:kNilOptions error:nil];
|
||||
}
|
||||
|
||||
return self.mj_keyValues;
|
||||
}
|
||||
|
||||
- (NSString *)mj_JSONString
|
||||
{
|
||||
if ([self isKindOfClass:[NSString class]]) {
|
||||
return (NSString *)self;
|
||||
} else if ([self isKindOfClass:[NSData class]]) {
|
||||
return [[NSString alloc] initWithData:(NSData *)self encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
return [[NSString alloc] initWithData:[self mj_JSONData] encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
@end
|
||||
70
Pods/MJExtension/MJExtension/NSObject+MJProperty.h
generated
Normal file
70
Pods/MJExtension/MJExtension/NSObject+MJProperty.h
generated
Normal file
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// NSObject+MJProperty.h
|
||||
// MJExtensionExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/17.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MJExtensionConst.h"
|
||||
|
||||
@class MJProperty;
|
||||
|
||||
/**
|
||||
* 遍历成员变量用的block
|
||||
*
|
||||
* @param property 成员的包装对象
|
||||
* @param stop YES代表停止遍历,NO代表继续遍历
|
||||
*/
|
||||
typedef void (^MJPropertiesEnumeration)(MJProperty *property, BOOL *stop);
|
||||
|
||||
/** 将属性名换为其他key去字典中取值 */
|
||||
typedef NSDictionary * (^MJReplacedKeyFromPropertyName)(void);
|
||||
typedef id (^MJReplacedKeyFromPropertyName121)(NSString *propertyName);
|
||||
/** 数组中需要转换的模型类 */
|
||||
typedef NSDictionary * (^MJObjectClassInArray)(void);
|
||||
/** 用于过滤字典中的值 */
|
||||
typedef id (^MJNewValueFromOldValue)(id object, id oldValue, MJProperty *property);
|
||||
|
||||
/**
|
||||
* 成员属性相关的扩展
|
||||
*/
|
||||
@interface NSObject (MJProperty)
|
||||
#pragma mark - 遍历
|
||||
/**
|
||||
* 遍历所有的成员
|
||||
*/
|
||||
+ (void)mj_enumerateProperties:(MJPropertiesEnumeration)enumeration;
|
||||
|
||||
#pragma mark - 新值配置
|
||||
/**
|
||||
* 用于过滤字典中的值
|
||||
*
|
||||
* @param newValueFormOldValue 用于过滤字典中的值
|
||||
*/
|
||||
+ (void)mj_setupNewValueFromOldValue:(MJNewValueFromOldValue)newValueFormOldValue;
|
||||
+ (id)mj_getNewValueFromObject:(__unsafe_unretained id)object oldValue:(__unsafe_unretained id)oldValue property:(__unsafe_unretained MJProperty *)property;
|
||||
|
||||
#pragma mark - key配置
|
||||
/**
|
||||
* 将属性名换为其他key去字典中取值
|
||||
*
|
||||
* @param replacedKeyFromPropertyName 将属性名换为其他key去字典中取值
|
||||
*/
|
||||
+ (void)mj_setupReplacedKeyFromPropertyName:(MJReplacedKeyFromPropertyName)replacedKeyFromPropertyName;
|
||||
/**
|
||||
* 将属性名换为其他key去字典中取值
|
||||
*
|
||||
* @param replacedKeyFromPropertyName121 将属性名换为其他key去字典中取值
|
||||
*/
|
||||
+ (void)mj_setupReplacedKeyFromPropertyName121:(MJReplacedKeyFromPropertyName121)replacedKeyFromPropertyName121;
|
||||
|
||||
#pragma mark - array model class配置
|
||||
/**
|
||||
* 数组中需要转换的模型类
|
||||
*
|
||||
* @param objectClassInArray 数组中需要转换的模型类
|
||||
*/
|
||||
+ (void)mj_setupObjectClassInArray:(MJObjectClassInArray)objectClassInArray;
|
||||
@end
|
||||
240
Pods/MJExtension/MJExtension/NSObject+MJProperty.m
generated
Normal file
240
Pods/MJExtension/MJExtension/NSObject+MJProperty.m
generated
Normal file
@@ -0,0 +1,240 @@
|
||||
//
|
||||
// NSObject+MJProperty.m
|
||||
// MJExtensionExample
|
||||
//
|
||||
// Created by MJ Lee on 15/4/17.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSObject+MJProperty.h"
|
||||
#import "NSObject+MJKeyValue.h"
|
||||
#import "NSObject+MJCoding.h"
|
||||
#import "NSObject+MJClass.h"
|
||||
#import "MJProperty.h"
|
||||
#import "MJFoundation.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wundeclared-selector"
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
|
||||
static const char MJReplacedKeyFromPropertyNameKey = '\0';
|
||||
static const char MJReplacedKeyFromPropertyName121Key = '\0';
|
||||
static const char MJNewValueFromOldValueKey = '\0';
|
||||
static const char MJObjectClassInArrayKey = '\0';
|
||||
|
||||
static const char MJCachedPropertiesKey = '\0';
|
||||
|
||||
dispatch_semaphore_t mje_signalSemaphore;
|
||||
dispatch_once_t mje_onceTokenSemaphore;
|
||||
|
||||
@implementation NSObject (Property)
|
||||
|
||||
+ (NSMutableDictionary *)mj_propertyDictForKey:(const void *)key
|
||||
{
|
||||
static NSMutableDictionary *replacedKeyFromPropertyNameDict;
|
||||
static NSMutableDictionary *replacedKeyFromPropertyName121Dict;
|
||||
static NSMutableDictionary *newValueFromOldValueDict;
|
||||
static NSMutableDictionary *objectClassInArrayDict;
|
||||
static NSMutableDictionary *cachedPropertiesDict;
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
replacedKeyFromPropertyNameDict = [NSMutableDictionary dictionary];
|
||||
replacedKeyFromPropertyName121Dict = [NSMutableDictionary dictionary];
|
||||
newValueFromOldValueDict = [NSMutableDictionary dictionary];
|
||||
objectClassInArrayDict = [NSMutableDictionary dictionary];
|
||||
cachedPropertiesDict = [NSMutableDictionary dictionary];
|
||||
});
|
||||
|
||||
if (key == &MJReplacedKeyFromPropertyNameKey) return replacedKeyFromPropertyNameDict;
|
||||
if (key == &MJReplacedKeyFromPropertyName121Key) return replacedKeyFromPropertyName121Dict;
|
||||
if (key == &MJNewValueFromOldValueKey) return newValueFromOldValueDict;
|
||||
if (key == &MJObjectClassInArrayKey) return objectClassInArrayDict;
|
||||
if (key == &MJCachedPropertiesKey) return cachedPropertiesDict;
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - --私有方法--
|
||||
+ (id)mj_propertyKey:(NSString *)propertyName
|
||||
{
|
||||
MJExtensionAssertParamNotNil2(propertyName, nil);
|
||||
|
||||
__block id key = nil;
|
||||
// 查看有没有需要替换的key
|
||||
if ([self respondsToSelector:@selector(mj_replacedKeyFromPropertyName121:)]) {
|
||||
key = [self mj_replacedKeyFromPropertyName121:propertyName];
|
||||
}
|
||||
|
||||
// 调用block
|
||||
if (!key) {
|
||||
[self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
|
||||
MJReplacedKeyFromPropertyName121 block = objc_getAssociatedObject(c, &MJReplacedKeyFromPropertyName121Key);
|
||||
if (block) {
|
||||
key = block(propertyName);
|
||||
}
|
||||
if (key) *stop = YES;
|
||||
}];
|
||||
}
|
||||
|
||||
// 查看有没有需要替换的key
|
||||
if ((!key || [key isEqual:propertyName]) && [self respondsToSelector:@selector(mj_replacedKeyFromPropertyName)]) {
|
||||
key = [self mj_replacedKeyFromPropertyName][propertyName];
|
||||
}
|
||||
|
||||
if (!key || [key isEqual:propertyName]) {
|
||||
[self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
|
||||
NSDictionary *dict = objc_getAssociatedObject(c, &MJReplacedKeyFromPropertyNameKey);
|
||||
if (dict) {
|
||||
key = dict[propertyName];
|
||||
}
|
||||
if (key && ![key isEqual:propertyName]) *stop = YES;
|
||||
}];
|
||||
}
|
||||
|
||||
// 2.用属性名作为key
|
||||
if (!key) key = propertyName;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
+ (Class)mj_propertyObjectClassInArray:(NSString *)propertyName
|
||||
{
|
||||
__block id clazz = nil;
|
||||
if ([self respondsToSelector:@selector(mj_objectClassInArray)]) {
|
||||
clazz = [self mj_objectClassInArray][propertyName];
|
||||
}
|
||||
|
||||
if (!clazz) {
|
||||
[self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
|
||||
NSDictionary *dict = objc_getAssociatedObject(c, &MJObjectClassInArrayKey);
|
||||
if (dict) {
|
||||
clazz = dict[propertyName];
|
||||
}
|
||||
if (clazz) *stop = YES;
|
||||
}];
|
||||
}
|
||||
|
||||
// 如果是NSString类型
|
||||
if ([clazz isKindOfClass:[NSString class]]) {
|
||||
clazz = NSClassFromString(clazz);
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
|
||||
#pragma mark - --公共方法--
|
||||
+ (void)mj_enumerateProperties:(MJPropertiesEnumeration)enumeration
|
||||
{
|
||||
// 获得成员变量
|
||||
NSArray *cachedProperties = [self mj_properties];
|
||||
// 遍历成员变量
|
||||
BOOL stop = NO;
|
||||
for (MJProperty *property in cachedProperties) {
|
||||
enumeration(property, &stop);
|
||||
if (stop) break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 公共方法
|
||||
+ (NSArray *)mj_properties
|
||||
{
|
||||
MJExtensionSemaphoreCreate
|
||||
MJ_LOCK(mje_signalSemaphore);
|
||||
NSMutableDictionary *cachedInfo = [self mj_propertyDictForKey:&MJCachedPropertiesKey];
|
||||
NSMutableArray *cachedProperties = cachedInfo[NSStringFromClass(self)];
|
||||
if (cachedProperties == nil) {
|
||||
cachedProperties = [NSMutableArray array];
|
||||
|
||||
[self mj_enumerateClasses:^(__unsafe_unretained Class c, BOOL *stop) {
|
||||
// 1.获得所有的成员变量
|
||||
unsigned int outCount = 0;
|
||||
objc_property_t *properties = class_copyPropertyList(c, &outCount);
|
||||
|
||||
// 2.遍历每一个成员变量
|
||||
for (unsigned int i = 0; i<outCount; i++) {
|
||||
MJProperty *property = [MJProperty cachedPropertyWithProperty:properties[i]];
|
||||
// 过滤掉Foundation框架类里面的属性
|
||||
if ([MJFoundation isClassFromFoundation:property.srcClass]) continue;
|
||||
// 过滤掉`hash`, `superclass`, `description`, `debugDescription`
|
||||
if ([MJFoundation isFromNSObjectProtocolProperty:property.name]) continue;
|
||||
|
||||
property.srcClass = c;
|
||||
[property setOriginKey:[self mj_propertyKey:property.name] forClass:self];
|
||||
[property setObjectClassInArray:[self mj_propertyObjectClassInArray:property.name] forClass:self];
|
||||
[cachedProperties addObject:property];
|
||||
}
|
||||
|
||||
// 3.释放内存
|
||||
free(properties);
|
||||
}];
|
||||
|
||||
cachedInfo[NSStringFromClass(self)] = cachedProperties;
|
||||
}
|
||||
NSArray *properties = [cachedProperties copy];
|
||||
MJ_UNLOCK(mje_signalSemaphore);
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
#pragma mark - 新值配置
|
||||
+ (void)mj_setupNewValueFromOldValue:(MJNewValueFromOldValue)newValueFormOldValue {
|
||||
MJExtensionSemaphoreCreate
|
||||
MJ_LOCK(mje_signalSemaphore);
|
||||
objc_setAssociatedObject(self, &MJNewValueFromOldValueKey, newValueFormOldValue, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
MJ_UNLOCK(mje_signalSemaphore);
|
||||
}
|
||||
|
||||
+ (id)mj_getNewValueFromObject:(__unsafe_unretained id)object oldValue:(__unsafe_unretained id)oldValue property:(MJProperty *__unsafe_unretained)property{
|
||||
// 如果有实现方法
|
||||
if ([object respondsToSelector:@selector(mj_newValueFromOldValue:property:)]) {
|
||||
return [object mj_newValueFromOldValue:oldValue property:property];
|
||||
}
|
||||
|
||||
MJExtensionSemaphoreCreate
|
||||
MJ_LOCK(mje_signalSemaphore);
|
||||
// 查看静态设置
|
||||
__block id newValue = oldValue;
|
||||
[self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
|
||||
MJNewValueFromOldValue block = objc_getAssociatedObject(c, &MJNewValueFromOldValueKey);
|
||||
if (block) {
|
||||
newValue = block(object, oldValue, property);
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
MJ_UNLOCK(mje_signalSemaphore);
|
||||
return newValue;
|
||||
}
|
||||
|
||||
+ (void)mj_removeCachedProperties {
|
||||
MJExtensionSemaphoreCreate
|
||||
MJ_LOCK(mje_signalSemaphore);
|
||||
[[self mj_propertyDictForKey:&MJCachedPropertiesKey] removeAllObjects];
|
||||
MJ_UNLOCK(mje_signalSemaphore);
|
||||
}
|
||||
|
||||
#pragma mark - array model class配置
|
||||
+ (void)mj_setupObjectClassInArray:(MJObjectClassInArray)objectClassInArray
|
||||
{
|
||||
[self mj_setupBlockReturnValue:objectClassInArray key:&MJObjectClassInArrayKey];
|
||||
|
||||
[self mj_removeCachedProperties];
|
||||
}
|
||||
|
||||
#pragma mark - key配置
|
||||
|
||||
+ (void)mj_setupReplacedKeyFromPropertyName:(MJReplacedKeyFromPropertyName)replacedKeyFromPropertyName {
|
||||
[self mj_setupBlockReturnValue:replacedKeyFromPropertyName key:&MJReplacedKeyFromPropertyNameKey];
|
||||
|
||||
[self mj_removeCachedProperties];
|
||||
}
|
||||
|
||||
+ (void)mj_setupReplacedKeyFromPropertyName121:(MJReplacedKeyFromPropertyName121)replacedKeyFromPropertyName121 {
|
||||
MJExtensionSemaphoreCreate
|
||||
MJ_LOCK(mje_signalSemaphore);
|
||||
objc_setAssociatedObject(self, &MJReplacedKeyFromPropertyName121Key, replacedKeyFromPropertyName121, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
|
||||
[[self mj_propertyDictForKey:&MJCachedPropertiesKey] removeAllObjects];
|
||||
MJ_UNLOCK(mje_signalSemaphore);
|
||||
}
|
||||
@end
|
||||
#pragma clang diagnostic pop
|
||||
33
Pods/MJExtension/MJExtension/NSString+MJExtension.h
generated
Normal file
33
Pods/MJExtension/MJExtension/NSString+MJExtension.h
generated
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// NSString+MJExtension.h
|
||||
// MJExtensionExample
|
||||
//
|
||||
// Created by MJ Lee on 15/6/7.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MJExtensionConst.h"
|
||||
|
||||
@interface NSString (MJExtension)
|
||||
/**
|
||||
* 驼峰转下划线(loveYou -> love_you)
|
||||
*/
|
||||
- (NSString *)mj_underlineFromCamel;
|
||||
/**
|
||||
* 下划线转驼峰(love_you -> loveYou)
|
||||
*/
|
||||
- (NSString *)mj_camelFromUnderline;
|
||||
/**
|
||||
* 首字母变大写
|
||||
*/
|
||||
- (NSString *)mj_firstCharUpper;
|
||||
/**
|
||||
* 首字母变小写
|
||||
*/
|
||||
- (NSString *)mj_firstCharLower;
|
||||
|
||||
- (BOOL)mj_isPureInt;
|
||||
|
||||
- (NSURL *)mj_url;
|
||||
@end
|
||||
80
Pods/MJExtension/MJExtension/NSString+MJExtension.m
generated
Normal file
80
Pods/MJExtension/MJExtension/NSString+MJExtension.m
generated
Normal file
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// NSString+MJExtension.m
|
||||
// MJExtensionExample
|
||||
//
|
||||
// Created by MJ Lee on 15/6/7.
|
||||
// Copyright (c) 2015年 小码哥. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSString+MJExtension.h"
|
||||
|
||||
@implementation NSString (MJExtension)
|
||||
- (NSString *)mj_underlineFromCamel
|
||||
{
|
||||
if (self.length == 0) return self;
|
||||
NSMutableString *string = [NSMutableString string];
|
||||
for (NSUInteger i = 0; i<self.length; i++) {
|
||||
unichar c = [self characterAtIndex:i];
|
||||
NSString *cString = [NSString stringWithFormat:@"%c", c];
|
||||
NSString *cStringLower = [cString lowercaseString];
|
||||
if ([cString isEqualToString:cStringLower]) {
|
||||
[string appendString:cStringLower];
|
||||
} else {
|
||||
[string appendString:@"_"];
|
||||
[string appendString:cStringLower];
|
||||
}
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
- (NSString *)mj_camelFromUnderline
|
||||
{
|
||||
if (self.length == 0) return self;
|
||||
NSMutableString *string = [NSMutableString string];
|
||||
NSArray *cmps = [self componentsSeparatedByString:@"_"];
|
||||
for (NSUInteger i = 0; i<cmps.count; i++) {
|
||||
NSString *cmp = cmps[i];
|
||||
if (i && cmp.length) {
|
||||
[string appendString:[NSString stringWithFormat:@"%c", [cmp characterAtIndex:0]].uppercaseString];
|
||||
if (cmp.length >= 2) [string appendString:[cmp substringFromIndex:1]];
|
||||
} else {
|
||||
[string appendString:cmp];
|
||||
}
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
- (NSString *)mj_firstCharLower
|
||||
{
|
||||
if (self.length == 0) return self;
|
||||
NSMutableString *string = [NSMutableString string];
|
||||
[string appendString:[NSString stringWithFormat:@"%c", [self characterAtIndex:0]].lowercaseString];
|
||||
if (self.length >= 2) [string appendString:[self substringFromIndex:1]];
|
||||
return string;
|
||||
}
|
||||
|
||||
- (NSString *)mj_firstCharUpper
|
||||
{
|
||||
if (self.length == 0) return self;
|
||||
NSMutableString *string = [NSMutableString string];
|
||||
[string appendString:[NSString stringWithFormat:@"%c", [self characterAtIndex:0]].uppercaseString];
|
||||
if (self.length >= 2) [string appendString:[self substringFromIndex:1]];
|
||||
return string;
|
||||
}
|
||||
|
||||
- (BOOL)mj_isPureInt
|
||||
{
|
||||
NSScanner *scan = [NSScanner scannerWithString:self];
|
||||
int val;
|
||||
return [scan scanInt:&val] && [scan isAtEnd];
|
||||
}
|
||||
|
||||
- (NSURL *)mj_url
|
||||
{
|
||||
// [self stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"!$&'()*+,-./:;=?@_~%#[]"]];
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
|
||||
return [NSURL URLWithString:(NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, (CFStringRef)@"!$&'()*+,-./:;=?@_~%#[]", NULL,kCFStringEncodingUTF8))];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
@end
|
||||
14
Pods/MJExtension/MJExtension/PrivacyInfo.xcprivacy
generated
Normal file
14
Pods/MJExtension/MJExtension/PrivacyInfo.xcprivacy
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrivacyTracking</key>
|
||||
<false/>
|
||||
<key>NSPrivacyTrackingDomains</key>
|
||||
<array/>
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array/>
|
||||
<key>NSPrivacyCollectedDataTypes</key>
|
||||
<array/>
|
||||
</dict>
|
||||
</plist>
|
||||
Reference in New Issue
Block a user