首次提交
This commit is contained in:
19
Pods/MJExtension/LICENSE
generated
Executable file
19
Pods/MJExtension/LICENSE
generated
Executable file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2013-2019 MJExtension (https://github.com/CoderMJLee/MJExtension)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
27
Pods/MJExtension/MJExtension/MJExtension.h
generated
Executable file
27
Pods/MJExtension/MJExtension/MJExtension.h
generated
Executable 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
Executable file
111
Pods/MJExtension/MJExtension/MJExtensionConst.h
generated
Executable 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
Executable file
27
Pods/MJExtension/MJExtension/MJExtensionConst.m
generated
Executable 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
Executable file
16
Pods/MJExtension/MJExtension/MJFoundation.h
generated
Executable 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
Executable file
70
Pods/MJExtension/MJExtension/MJFoundation.m
generated
Executable 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
Executable file
53
Pods/MJExtension/MJExtension/MJProperty.h
generated
Executable 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
Executable file
211
Pods/MJExtension/MJExtension/MJProperty.m
generated
Executable 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
Executable file
30
Pods/MJExtension/MJExtension/MJPropertyKey.h
generated
Executable 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
Executable file
25
Pods/MJExtension/MJExtension/MJPropertyKey.m
generated
Executable 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
Executable file
90
Pods/MJExtension/MJExtension/NSObject+MJClass.h
generated
Executable 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
Executable file
174
Pods/MJExtension/MJExtension/NSObject+MJClass.m
generated
Executable 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
Executable file
70
Pods/MJExtension/MJExtension/NSObject+MJProperty.h
generated
Executable 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
Executable file
240
Pods/MJExtension/MJExtension/NSObject+MJProperty.m
generated
Executable 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
Executable file
33
Pods/MJExtension/MJExtension/NSString+MJExtension.h
generated
Executable 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
Executable file
80
Pods/MJExtension/MJExtension/NSString+MJExtension.m
generated
Executable 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
|
||||
637
Pods/MJExtension/README.md
generated
Executable file
637
Pods/MJExtension/README.md
generated
Executable file
@@ -0,0 +1,637 @@
|
||||
MJExtension
|
||||
===
|
||||
[](https://github.com/apple/swift-package-manager)
|
||||
[](https://github.com/Carthage/Carthage)
|
||||
[](https://cocoapods.org/pods/MJExtension)
|
||||

|
||||
|
||||
- A fast, convenient and nonintrusive conversion framework between JSON and model.
|
||||
- 转换速度快、使用简单方便的字典转模型框架
|
||||
|
||||
[📜✍🏻**Release Notes**: more details](https://github.com/CoderMJLee/MJExtension/releases)
|
||||
|
||||
## Contents
|
||||
|
||||
* [Getting Started 【开始使用】](#Getting_Started)
|
||||
* [Features 【能做什么】](#Features)
|
||||
* [Installation 【安装】](#Installation)
|
||||
* [Examples 【示例】](#Examples)
|
||||
* [Usage in Swift](#usage_in_swift)
|
||||
* [JSON -> Model](#JSON_Model)
|
||||
* [JSONString -> Model](#JSONString_Model)
|
||||
* [Model contains model](#Model_contains_model)
|
||||
* [Model contains model-array](#Model_contains_model_array)
|
||||
* [Model name - JSON key mapping](#Model_name_JSON_key_mapping)
|
||||
* [JSON array -> model array](#JSON_array_model_array)
|
||||
* [Model -> JSON](#Model_JSON)
|
||||
* [Model array -> JSON array](#Model_array_JSON_array)
|
||||
* [Core Data](#Core_Data)
|
||||
* [Coding](#Coding)
|
||||
* [Secure Coding](#SecureCoding)
|
||||
* [Camel -> underline](#Camel_underline)
|
||||
* [NSString -> NSDate, nil -> @""](#NSString_NSDate)
|
||||
* [NSDate -> NSString](#NSDate_NSString)
|
||||
* [More use cases](#More_use_cases)
|
||||
|
||||
---
|
||||
|
||||
## <a id="Getting_Started"></a> Getting Started【开始使用】
|
||||
|
||||
### <a id="Features"></a> Features【能做什么】
|
||||
- MJExtension是一套字典和模型之间互相转换的超轻量级框架
|
||||
* `JSON` --> `Model`、`Core Data Model`
|
||||
* `JSONString` --> `Model`、`Core Data Model`
|
||||
* `Model`、`Core Data Model` --> `JSON`
|
||||
* `JSON Array` --> `Model Array`、`Core Data Model Array`
|
||||
* `JSONString` --> `Model Array`、`Core Data Model Array`
|
||||
* `Model Array`、`Core Data Model Array` --> `JSON Array`
|
||||
* Coding all properties of a model with only one line of code.
|
||||
* 只需要一行代码,就能实现模型的所有属性进行Coding / SecureCoding(归档和解档)
|
||||
|
||||
### <a id="Installation"></a> Installation【安装】
|
||||
|
||||
#### CocoaPods【使用CocoaPods】
|
||||
|
||||
```ruby
|
||||
pod 'MJExtension'
|
||||
```
|
||||
|
||||
#### Carthage
|
||||
|
||||
```ruby
|
||||
github "CoderMJLee/MJExtension"
|
||||
```
|
||||
|
||||
#### Swift Package Manager
|
||||
|
||||
Released from [`3.4.0`](https://github.com/CoderMJLee/MJExtension/releases/)
|
||||
|
||||
#### Manually【手动导入】
|
||||
|
||||
- Drag all source files under folder `MJExtension` to your project.【将`MJExtension`文件夹中的所有源代码拽入项目中】
|
||||
- Import the main header file:`#import "MJExtension.h"`【导入主头文件:`#import "MJExtension.h"`】
|
||||
|
||||
## <a id="Examples"></a> Examples【示例】
|
||||
|
||||
**Add `MJKeyValue` protocol to your model if needed【如果有需要, 请在模型中加入 `MJKeyValue` 协议】**
|
||||
|
||||
### <a id="usage_in_swift"></a> Usage in Swift [关于在Swift中使用MJExtension] ‼️
|
||||
|
||||
> Example:
|
||||
>
|
||||
> - [Model - MJTester.swift](MJExtensionTests/SwiftModel/MJTester.swift)
|
||||
>
|
||||
> - [Usage - SwiftModelTests.swift](MJExtensionTests/SwiftModelTests.swift)
|
||||
|
||||
```swift
|
||||
@objc(MJTester)
|
||||
@objcMembers
|
||||
class MJTester: NSObject {
|
||||
// make sure to use `dynamic` attribute for basic type & must use as Non-Optional & must set initial value
|
||||
dynamic var isSpecialAgent: Bool = false
|
||||
dynamic var age: Int = 0
|
||||
|
||||
var name: String?
|
||||
var identifier: String?
|
||||
}
|
||||
```
|
||||
|
||||
1. `@objc` or `@objcMembers` attributes should be added to class or property for declaration of Objc accessibility [在 Swift4 之后, 请在属性前加 `@objc` 修饰或在类前增加 `@objcMembers`. 以保证 Swift 的属性能够暴露给 Objc 使用. ]
|
||||
2. If you let `Bool` & `Int` as property type, make sure that using `dynamic` to attribute it. It must be `Non-Optional` type and assign `a default value`.[如果要使用 `Bool` 和 `Int` 等 Swfit 专用基本类型, 请使用 `dynamic` 关键字修饰, 类型为 `Non-Optional`, 並且给定初始值.]
|
||||
|
||||
> 纯Swift版的JSON与Model转换框架已经开源上架
|
||||
>
|
||||
> - [KakaJSON](https://github.com/kakaopensource/KakaJSON)
|
||||
> - [中文教程](https://www.cnblogs.com/mjios/p/11352776.html)
|
||||
> - 如果你的项目是用Swift写的Model,墙裂推荐使用[KakaJSON](https://github.com/kakaopensource/KakaJSON)
|
||||
> - 已经对各种常用的数据场景进行了大量的单元测试
|
||||
> - 简单易用、功能丰富、转换快速
|
||||
|
||||
### <a id="JSON_Model"></a> The most simple JSON -> Model【最简单的字典转模型】
|
||||
|
||||
```objc
|
||||
typedef enum {
|
||||
SexMale,
|
||||
SexFemale
|
||||
} Sex;
|
||||
|
||||
@interface User : NSObject
|
||||
@property (copy, nonatomic) NSString *name;
|
||||
@property (copy, nonatomic) NSString *icon;
|
||||
@property (assign, nonatomic) unsigned int age;
|
||||
@property (copy, nonatomic) NSString *height;
|
||||
@property (strong, nonatomic) NSNumber *money;
|
||||
@property (assign, nonatomic) Sex sex;
|
||||
@property (assign, nonatomic, getter=isGay) BOOL gay;
|
||||
@end
|
||||
|
||||
/***********************************************/
|
||||
|
||||
NSDictionary *dict = @{
|
||||
@"name" : @"Jack",
|
||||
@"icon" : @"lufy.png",
|
||||
@"age" : @20,
|
||||
@"height" : @"1.55",
|
||||
@"money" : @100.9,
|
||||
@"sex" : @(SexFemale),
|
||||
@"gay" : @"true"
|
||||
// @"gay" : @"1"
|
||||
// @"gay" : @"NO"
|
||||
};
|
||||
|
||||
// JSON -> User
|
||||
User *user = [User mj_objectWithKeyValues:dict];
|
||||
|
||||
NSLog(@"name=%@, icon=%@, age=%zd, height=%@, money=%@, sex=%d, gay=%d", user.name, user.icon, user.age, user.height, user.money, user.sex, user.gay);
|
||||
// name=Jack, icon=lufy.png, age=20, height=1.550000, money=100.9, sex=1
|
||||
```
|
||||
|
||||
### <a id="JSONString_Model"></a> JSONString -> Model【JSON字符串转模型】
|
||||
|
||||
```objc
|
||||
// 1.Define a JSONString
|
||||
NSString *jsonString = @"{\"name\":\"Jack\", \"icon\":\"lufy.png\", \"age\":20}";
|
||||
|
||||
// 2.JSONString -> User
|
||||
User *user = [User mj_objectWithKeyValues:jsonString];
|
||||
|
||||
// 3.Print user's properties
|
||||
NSLog(@"name=%@, icon=%@, age=%d", user.name, user.icon, user.age);
|
||||
// name=Jack, icon=lufy.png, age=20
|
||||
```
|
||||
|
||||
### <a id="Model_contains_model"></a> Model contains model【模型中嵌套模型】
|
||||
|
||||
```objc
|
||||
@interface Status : NSObject
|
||||
@property (copy, nonatomic) NSString *text;
|
||||
@property (strong, nonatomic) User *user;
|
||||
@property (strong, nonatomic) Status *retweetedStatus;
|
||||
@end
|
||||
|
||||
/***********************************************/
|
||||
|
||||
NSDictionary *dict = @{
|
||||
@"text" : @"Agree!Nice weather!",
|
||||
@"user" : @{
|
||||
@"name" : @"Jack",
|
||||
@"icon" : @"lufy.png"
|
||||
},
|
||||
@"retweetedStatus" : @{
|
||||
@"text" : @"Nice weather!",
|
||||
@"user" : @{
|
||||
@"name" : @"Rose",
|
||||
@"icon" : @"nami.png"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// JSON -> Status
|
||||
Status *status = [Status mj_objectWithKeyValues:dict];
|
||||
|
||||
NSString *text = status.text;
|
||||
NSString *name = status.user.name;
|
||||
NSString *icon = status.user.icon;
|
||||
NSLog(@"text=%@, name=%@, icon=%@", text, name, icon);
|
||||
// text=Agree!Nice weather!, name=Jack, icon=lufy.png
|
||||
|
||||
NSString *text2 = status.retweetedStatus.text;
|
||||
NSString *name2 = status.retweetedStatus.user.name;
|
||||
NSString *icon2 = status.retweetedStatus.user.icon;
|
||||
NSLog(@"text2=%@, name2=%@, icon2=%@", text2, name2, icon2);
|
||||
// text2=Nice weather!, name2=Rose, icon2=nami.png
|
||||
```
|
||||
|
||||
### <a id="Model_contains_model_array"></a> Model contains model-array【模型中有个数组属性,数组里面又要装着其他模型】
|
||||
|
||||
```objc
|
||||
@interface Ad : NSObject
|
||||
@property (copy, nonatomic) NSString *image;
|
||||
@property (copy, nonatomic) NSString *url;
|
||||
@end
|
||||
|
||||
@interface StatusResult : NSObject
|
||||
/** Contatins status model */
|
||||
@property (strong, nonatomic) NSMutableArray *statuses;
|
||||
/** Contatins ad model */
|
||||
@property (strong, nonatomic) NSArray *ads;
|
||||
@property (strong, nonatomic) NSNumber *totalNumber;
|
||||
@end
|
||||
|
||||
/***********************************************/
|
||||
|
||||
// Tell MJExtension what type of model will be contained in statuses and ads.
|
||||
[StatusResult mj_setupObjectClassInArray:^NSDictionary *{
|
||||
return @{
|
||||
@"statuses" : @"Status",
|
||||
// @"statuses" : [Status class],
|
||||
@"ads" : @"Ad"
|
||||
// @"ads" : [Ad class]
|
||||
};
|
||||
}];
|
||||
// Equals: StatusResult.m implements +mj_objectClassInArray method.
|
||||
|
||||
NSDictionary *dict = @{
|
||||
@"statuses" : @[
|
||||
@{
|
||||
@"text" : @"Nice weather!",
|
||||
@"user" : @{
|
||||
@"name" : @"Rose",
|
||||
@"icon" : @"nami.png"
|
||||
}
|
||||
},
|
||||
@{
|
||||
@"text" : @"Go camping tomorrow!",
|
||||
@"user" : @{
|
||||
@"name" : @"Jack",
|
||||
@"icon" : @"lufy.png"
|
||||
}
|
||||
}
|
||||
],
|
||||
@"ads" : @[
|
||||
@{
|
||||
@"image" : @"ad01.png",
|
||||
@"url" : @"http://www.ad01.com"
|
||||
},
|
||||
@{
|
||||
@"image" : @"ad02.png",
|
||||
@"url" : @"http://www.ad02.com"
|
||||
}
|
||||
],
|
||||
@"totalNumber" : @"2014"
|
||||
};
|
||||
|
||||
// JSON -> StatusResult
|
||||
StatusResult *result = [StatusResult mj_objectWithKeyValues:dict];
|
||||
|
||||
NSLog(@"totalNumber=%@", result.totalNumber);
|
||||
// totalNumber=2014
|
||||
|
||||
// Printing
|
||||
for (Status *status in result.statuses) {
|
||||
NSString *text = status.text;
|
||||
NSString *name = status.user.name;
|
||||
NSString *icon = status.user.icon;
|
||||
NSLog(@"text=%@, name=%@, icon=%@", text, name, icon);
|
||||
}
|
||||
// text=Nice weather!, name=Rose, icon=nami.png
|
||||
// text=Go camping tomorrow!, name=Jack, icon=lufy.png
|
||||
|
||||
// Printing
|
||||
for (Ad *ad in result.ads) {
|
||||
NSLog(@"image=%@, url=%@", ad.image, ad.url);
|
||||
}
|
||||
// image=ad01.png, url=http://www.ad01.com
|
||||
// image=ad02.png, url=http://www.ad02.com
|
||||
```
|
||||
|
||||
### <a id="Model_name_JSON_key_mapping"></a> Model name - JSON key mapping【模型中的属性名和字典中的key不相同(或者需要多级映射)】
|
||||
|
||||
```objc
|
||||
@interface Bag : NSObject
|
||||
@property (copy, nonatomic) NSString *name;
|
||||
@property (assign, nonatomic) double price;
|
||||
@end
|
||||
|
||||
@interface Student : NSObject
|
||||
@property (copy, nonatomic) NSString *ID;
|
||||
@property (copy, nonatomic) NSString *desc;
|
||||
@property (copy, nonatomic) NSString *nowName;
|
||||
@property (copy, nonatomic) NSString *oldName;
|
||||
@property (copy, nonatomic) NSString *nameChangedTime;
|
||||
@property (strong, nonatomic) Bag *bag;
|
||||
@end
|
||||
|
||||
/***********************************************/
|
||||
|
||||
// How to map
|
||||
[Student mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
|
||||
return @{
|
||||
@"ID" : @"id",
|
||||
@"desc" : @"description",
|
||||
@"oldName" : @"name.oldName",
|
||||
@"nowName" : @"name.newName",
|
||||
@"nameChangedTime" : @"name.info[1].nameChangedTime",
|
||||
@"bag" : @"other.bag"
|
||||
};
|
||||
}];
|
||||
// Equals: Student.m implements +mj_replacedKeyFromPropertyName method.
|
||||
|
||||
NSDictionary *dict = @{
|
||||
@"id" : @"20",
|
||||
@"description" : @"kids",
|
||||
@"name" : @{
|
||||
@"newName" : @"lufy",
|
||||
@"oldName" : @"kitty",
|
||||
@"info" : @[
|
||||
@"test-data",
|
||||
@{
|
||||
@"nameChangedTime" : @"2013-08"
|
||||
}
|
||||
]
|
||||
},
|
||||
@"other" : @{
|
||||
@"bag" : @{
|
||||
@"name" : @"a red bag",
|
||||
@"price" : @100.7
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// JSON -> Student
|
||||
Student *stu = [Student mj_objectWithKeyValues:dict];
|
||||
|
||||
// Printing
|
||||
NSLog(@"ID=%@, desc=%@, oldName=%@, nowName=%@, nameChangedTime=%@",
|
||||
stu.ID, stu.desc, stu.oldName, stu.nowName, stu.nameChangedTime);
|
||||
// ID=20, desc=kids, oldName=kitty, nowName=lufy, nameChangedTime=2013-08
|
||||
NSLog(@"bagName=%@, bagPrice=%f", stu.bag.name, stu.bag.price);
|
||||
// bagName=a red bag, bagPrice=100.700000
|
||||
```
|
||||
|
||||
|
||||
### <a id="JSON_array_model_array"></a> JSON array -> model array【将一个字典数组转成模型数组】
|
||||
|
||||
```objc
|
||||
NSArray *dictArray = @[
|
||||
@{
|
||||
@"name" : @"Jack",
|
||||
@"icon" : @"lufy.png"
|
||||
},
|
||||
@{
|
||||
@"name" : @"Rose",
|
||||
@"icon" : @"nami.png"
|
||||
}
|
||||
];
|
||||
|
||||
// JSON array -> User array
|
||||
NSArray *userArray = [User mj_objectArrayWithKeyValuesArray:dictArray];
|
||||
|
||||
// Printing
|
||||
for (User *user in userArray) {
|
||||
NSLog(@"name=%@, icon=%@", user.name, user.icon);
|
||||
}
|
||||
// name=Jack, icon=lufy.png
|
||||
// name=Rose, icon=nami.png
|
||||
```
|
||||
|
||||
### <a id="Model_JSON"></a> Model -> JSON【将一个模型转成字典】
|
||||
```objc
|
||||
// New model
|
||||
User *user = [[User alloc] init];
|
||||
user.name = @"Jack";
|
||||
user.icon = @"lufy.png";
|
||||
|
||||
Status *status = [[Status alloc] init];
|
||||
status.user = user;
|
||||
status.text = @"Nice mood!";
|
||||
|
||||
// Status -> JSON
|
||||
NSDictionary *statusDict = status.mj_keyValues;
|
||||
NSLog(@"%@", statusDict);
|
||||
/*
|
||||
{
|
||||
text = "Nice mood!";
|
||||
user = {
|
||||
icon = "lufy.png";
|
||||
name = Jack;
|
||||
};
|
||||
}
|
||||
*/
|
||||
|
||||
// More complex situation
|
||||
Student *stu = [[Student alloc] init];
|
||||
stu.ID = @"123";
|
||||
stu.oldName = @"rose";
|
||||
stu.nowName = @"jack";
|
||||
stu.desc = @"handsome";
|
||||
stu.nameChangedTime = @"2018-09-08";
|
||||
|
||||
Bag *bag = [[Bag alloc] init];
|
||||
bag.name = @"a red bag";
|
||||
bag.price = 205;
|
||||
stu.bag = bag;
|
||||
|
||||
NSDictionary *stuDict = stu.mj_keyValues;
|
||||
NSLog(@"%@", stuDict);
|
||||
/*
|
||||
{
|
||||
ID = 123;
|
||||
bag = {
|
||||
name = "\U5c0f\U4e66\U5305";
|
||||
price = 205;
|
||||
};
|
||||
desc = handsome;
|
||||
nameChangedTime = "2018-09-08";
|
||||
nowName = jack;
|
||||
oldName = rose;
|
||||
}
|
||||
*/
|
||||
```
|
||||
|
||||
### <a id="Model_array_JSON_array"></a> Model array -> JSON array【将一个模型数组转成字典数组】
|
||||
|
||||
```objc
|
||||
// New model array
|
||||
User *user1 = [[User alloc] init];
|
||||
user1.name = @"Jack";
|
||||
user1.icon = @"lufy.png";
|
||||
|
||||
User *user2 = [[User alloc] init];
|
||||
user2.name = @"Rose";
|
||||
user2.icon = @"nami.png";
|
||||
|
||||
NSArray *userArray = @[user1, user2];
|
||||
|
||||
// Model array -> JSON array
|
||||
NSArray *dictArray = [User mj_keyValuesArrayWithObjectArray:userArray];
|
||||
NSLog(@"%@", dictArray);
|
||||
/*
|
||||
(
|
||||
{
|
||||
icon = "lufy.png";
|
||||
name = Jack;
|
||||
},
|
||||
{
|
||||
icon = "nami.png";
|
||||
name = Rose;
|
||||
}
|
||||
)
|
||||
*/
|
||||
```
|
||||
|
||||
### <a id="Core_Data"></a> Core Data
|
||||
|
||||
```swift
|
||||
func json2CoreDataObject() {
|
||||
context.performAndWait {
|
||||
let object = MJCoreDataTester.mj_object(withKeyValues: Values.testJSONObject, context: context)
|
||||
// use the object
|
||||
}
|
||||
}
|
||||
|
||||
func coreDataObject2JSON() {
|
||||
context.performAndWait {
|
||||
let dict = coreDataObject.mj_keyValues()
|
||||
// use dict
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <a id="Coding"></a> Coding (Archive & Unarchive methods are deprecated in iOS 12)
|
||||
|
||||
```objc
|
||||
#import "MJExtension.h"
|
||||
|
||||
@implementation MJBag
|
||||
// NSCoding Implementation
|
||||
MJCodingImplementation
|
||||
@end
|
||||
|
||||
/***********************************************/
|
||||
|
||||
// what properties not to be coded
|
||||
[MJBag mj_setupIgnoredCodingPropertyNames:^NSArray *{
|
||||
return @[@"name"];
|
||||
}];
|
||||
// Equals: MJBag.m implements +mj_ignoredCodingPropertyNames method.
|
||||
|
||||
// Create model
|
||||
MJBag *bag = [[MJBag alloc] init];
|
||||
bag.name = @"Red bag";
|
||||
bag.price = 200.8;
|
||||
|
||||
NSString *file = [NSHomeDirectory() stringByAppendingPathComponent:@"Desktop/bag.data"];
|
||||
// Encoding by archiving
|
||||
[NSKeyedArchiver archiveRootObject:bag toFile:file];
|
||||
|
||||
// Decoding by unarchiving
|
||||
MJBag *decodedBag = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
|
||||
NSLog(@"name=%@, price=%f", decodedBag.name, decodedBag.price);
|
||||
// name=(null), price=200.800000
|
||||
```
|
||||
|
||||
### <a id="SecureCoding"></a> Secure Coding
|
||||
|
||||
Using `MJSecureCodingImplementation(class, isSupport)` macro.
|
||||
|
||||
```objc
|
||||
@import MJExtension;
|
||||
|
||||
// NSSecureCoding Implementation
|
||||
MJSecureCodingImplementation(MJBag, YES)
|
||||
|
||||
@implementation MJBag
|
||||
@end
|
||||
|
||||
/***********************************************/
|
||||
|
||||
// what properties not to be coded
|
||||
[MJBag mj_setupIgnoredCodingPropertyNames:^NSArray *{
|
||||
return @[@"name"];
|
||||
}];
|
||||
// Equals: MJBag.m implements +mj_ignoredCodingPropertyNames method.
|
||||
|
||||
// Create model
|
||||
MJBag *bag = [[MJBag alloc] init];
|
||||
bag.name = @"Red bag";
|
||||
bag.price = 200.8;
|
||||
bag.isBig = YES;
|
||||
bag.weight = 200;
|
||||
|
||||
NSString *file = [NSTemporaryDirectory() stringByAppendingPathComponent:@"bag.data"];
|
||||
|
||||
NSError *error = nil;
|
||||
// Encoding by archiving
|
||||
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:bag requiringSecureCoding:YES error:&error];
|
||||
[data writeToFile:file atomically:true];
|
||||
|
||||
// Decoding by unarchiving
|
||||
NSData *readData = [NSFileManager.defaultManager contentsAtPath:file];
|
||||
error = nil;
|
||||
MJBag *decodedBag = [NSKeyedUnarchiver unarchivedObjectOfClass:MJBag.class fromData:readData error:&error];
|
||||
MJExtensionLog(@"name=%@, price=%f", decodedBag.name, decodedBag.price);
|
||||
```
|
||||
|
||||
### <a id="Camel_underline"></a> Camel -> underline【统一转换属性名(比如驼峰转下划线)】
|
||||
|
||||
```objc
|
||||
// Dog
|
||||
#import "MJExtension.h"
|
||||
|
||||
@implementation Dog
|
||||
+ (NSString *)mj_replacedKeyFromPropertyName121:(NSString *)propertyName
|
||||
{
|
||||
// nickName -> nick_name
|
||||
return [propertyName mj_underlineFromCamel];
|
||||
}
|
||||
@end
|
||||
|
||||
// NSDictionary
|
||||
NSDictionary *dict = @{
|
||||
@"nick_name" : @"旺财",
|
||||
@"sale_price" : @"10.5",
|
||||
@"run_speed" : @"100.9"
|
||||
};
|
||||
// NSDictionary -> Dog
|
||||
Dog *dog = [Dog mj_objectWithKeyValues:dict];
|
||||
|
||||
// printing
|
||||
NSLog(@"nickName=%@, scalePrice=%f runSpeed=%f", dog.nickName, dog.salePrice, dog.runSpeed);
|
||||
```
|
||||
|
||||
### <a id="NSString_NSDate"></a> NSString -> NSDate, nil -> @""【过滤字典的值(比如字符串日期处理为NSDate、字符串nil处理为@"")】
|
||||
```objc
|
||||
// Book
|
||||
#import "MJExtension.h"
|
||||
|
||||
@implementation Book
|
||||
- (id)mj_newValueFromOldValue:(id)oldValue property:(MJProperty *)property
|
||||
{
|
||||
if ([property.name isEqualToString:@"publisher"]) {
|
||||
if (oldValue == nil) return @"";
|
||||
} else if (property.type.typeClass == [NSDate class]) {
|
||||
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
|
||||
fmt.dateFormat = @"yyyy-MM-dd";
|
||||
return [fmt dateFromString:oldValue];
|
||||
}
|
||||
|
||||
return oldValue;
|
||||
}
|
||||
@end
|
||||
|
||||
// NSDictionary
|
||||
NSDictionary *dict = @{
|
||||
@"name" : @"5分钟突破iOS开发",
|
||||
@"publishedTime" : @"2011-09-10"
|
||||
};
|
||||
// NSDictionary -> Book
|
||||
Book *book = [Book mj_objectWithKeyValues:dict];
|
||||
|
||||
// printing
|
||||
NSLog(@"name=%@, publisher=%@, publishedTime=%@", book.name, book.publisher, book.publishedTime);
|
||||
```
|
||||
|
||||
### <a id="NSDate_NSString"></a> NSDate -> NSString【模型转字典时, 修改 Date 类型至 String】
|
||||
|
||||
```objc
|
||||
- (void)mj_objectDidConvertToKeyValues:(NSMutableDictionary *)keyValues {
|
||||
// NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
||||
// formatter.dateFormat = @"yyy-MM-dd";
|
||||
// should use sharedFormatter for better performance
|
||||
keyValues[@"publishedTime"] = [sharedFormatter stringFromDate:self.publishedTime];
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <a id="More_use_cases"></a> More use cases【更多用法】
|
||||
|
||||
- Please reference to `NSObject+MJKeyValue.h` and `NSObject+MJCoding.h`
|
||||
|
||||
|
||||
## 期待
|
||||
* 如果在使用过程中遇到BUG,希望你能Issues我,谢谢(或者尝试下载最新的框架代码看看BUG修复没有)
|
||||
* 如果在使用过程中发现功能不够用,希望你能Issues我,我非常想为这个框架增加更多好用的功能,谢谢
|
||||
* 如果你想为MJExtension输出代码,请拼命Pull Requests我
|
||||
|
||||
Reference in New Issue
Block a user