├── .gitignore ├── LICENSE ├── Podfile ├── Podfile.lock ├── Pods ├── MJExtension │ ├── LICENSE │ ├── MJExtension │ │ ├── MJExtension.h │ │ ├── MJExtensionConst.h │ │ ├── MJExtensionConst.m │ │ ├── MJFoundation.h │ │ ├── MJFoundation.m │ │ ├── MJProperty.h │ │ ├── MJProperty.m │ │ ├── MJPropertyKey.h │ │ ├── MJPropertyKey.m │ │ ├── MJPropertyType.h │ │ ├── MJPropertyType.m │ │ ├── NSObject+MJClass.h │ │ ├── NSObject+MJClass.m │ │ ├── NSObject+MJCoding.h │ │ ├── NSObject+MJCoding.m │ │ ├── NSObject+MJKeyValue.h │ │ ├── NSObject+MJKeyValue.m │ │ ├── NSObject+MJProperty.h │ │ ├── NSObject+MJProperty.m │ │ ├── NSString+MJExtension.h │ │ └── NSString+MJExtension.m │ └── README.md ├── Manifest.lock ├── Pods.xcodeproj │ └── project.pbxproj ├── Target Support Files │ ├── MJExtension │ │ ├── Info.plist │ │ ├── MJExtension-dummy.m │ │ ├── MJExtension-prefix.pch │ │ ├── MJExtension-umbrella.h │ │ ├── MJExtension.modulemap │ │ └── MJExtension.xcconfig │ ├── Pods-YBModelFileDemo │ │ ├── Info.plist │ │ ├── Pods-YBModelFileDemo-acknowledgements.markdown │ │ ├── Pods-YBModelFileDemo-acknowledgements.plist │ │ ├── Pods-YBModelFileDemo-dummy.m │ │ ├── Pods-YBModelFileDemo-frameworks.sh │ │ ├── Pods-YBModelFileDemo-resources.sh │ │ ├── Pods-YBModelFileDemo-umbrella.h │ │ ├── Pods-YBModelFileDemo.debug.xcconfig │ │ ├── Pods-YBModelFileDemo.modulemap │ │ └── Pods-YBModelFileDemo.release.xcconfig │ └── YYModel │ │ ├── Info.plist │ │ ├── YYModel-dummy.m │ │ ├── YYModel-prefix.pch │ │ ├── YYModel-umbrella.h │ │ ├── YYModel.modulemap │ │ └── YYModel.xcconfig └── YYModel │ ├── LICENSE │ ├── README.md │ └── YYModel │ ├── NSObject+YYModel.h │ ├── NSObject+YYModel.m │ ├── YYClassInfo.h │ ├── YYClassInfo.m │ └── YYModel.h ├── README.md ├── YBModelFile.podspec ├── YBModelFile ├── Handler │ ├── YBMFCodeForParentHandler.h │ ├── YBMFCodeForParentHandler.m │ ├── YBMFFileHHandler.h │ ├── YBMFFileHHandler.m │ ├── YBMFFileMHandler.h │ ├── YBMFFileMHandler.m │ ├── YBMFFileNoteHandler.h │ ├── YBMFFileNoteHandler.m │ ├── YBMFNameHandler.h │ └── YBMFNameHandler.m ├── Helper │ ├── NSObject+YBMFConfig.h │ └── NSObject+YBMFConfig.m ├── Node │ ├── YBMFNode.h │ └── YBMFNode.m ├── YBMFConfig.h ├── YBMFConfig.m ├── YBModelFile.h └── YBModelFile.m ├── YBModelFileDemo.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── YBModelFileDemo.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist └── YBModelFileDemo ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets ├── AppIcon.appiconset │ └── Contents.json └── Contents.json ├── Base.lproj ├── LaunchScreen.storyboard └── Main.storyboard ├── Info.plist ├── PrefixHeader.pch ├── ViewController.h ├── ViewController.m ├── WBTrendsModel3 ├── WBTrendsModel.h └── WBTrendsModel.m ├── main.m └── weibo_0.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots/**/*.png 56 | fastlane/test_output 57 | 58 | # Code Injection 59 | # 60 | # After new code Injection tools there's a generated folder /iOSInjectionProject 61 | # https://github.com/johnno1962/injectionforxcode 62 | 63 | iOSInjectionProject/ 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 杨波 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | platform:ios, '8.0' 2 | target ‘YBModelFileDemo’ do 3 | use_frameworks! 4 | 5 | pod 'YYModel' 6 | pod 'MJExtension' 7 | 8 | end 9 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - MJExtension (3.0.15.1) 3 | - YYModel (1.0.4) 4 | 5 | DEPENDENCIES: 6 | - MJExtension 7 | - YYModel 8 | 9 | SPEC REPOS: 10 | https://github.com/cocoapods/specs.git: 11 | - MJExtension 12 | - YYModel 13 | 14 | SPEC CHECKSUMS: 15 | MJExtension: 19bc33ce2eee2d319760f5622562cf581a6ff756 16 | YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30 17 | 18 | PODFILE CHECKSUM: 9364ab88efc702c5c257fea881b1332094290091 19 | 20 | COCOAPODS: 1.5.3 21 | -------------------------------------------------------------------------------- /Pods/MJExtension/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2015 MJExtension (https://github.com/CoderMJLee/MJExtension) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Pods/MJExtension/MJExtension/MJExtension.h: -------------------------------------------------------------------------------- 1 | // 2 | // MJExtension.h 3 | // MJExtension 4 | // 5 | // Created by mj on 14-1-15. 6 | // Copyright (c) 2014年 小码哥. All rights reserved. 7 | // 代码地址:https://github.com/CoderMJLee/MJExtension 8 | // 代码地址:http://code4app.com/ios/%E5%AD%97%E5%85%B8-JSON-%E4%B8%8E%E6%A8%A1%E5%9E%8B%E7%9A%84%E8%BD%AC%E6%8D%A2/5339992a933bf062608b4c57 9 | 10 | #import "NSObject+MJCoding.h" 11 | #import "NSObject+MJProperty.h" 12 | #import "NSObject+MJClass.h" 13 | #import "NSObject+MJKeyValue.h" 14 | #import "NSString+MJExtension.h" 15 | #import "MJExtensionConst.h" -------------------------------------------------------------------------------- /Pods/MJExtension/MJExtension/MJExtensionConst.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __MJExtensionConst__H__ 3 | #define __MJExtensionConst__H__ 4 | 5 | #import 6 | 7 | // 信号量 8 | #define MJExtensionSemaphoreCreate \ 9 | static dispatch_semaphore_t signalSemaphore; \ 10 | static dispatch_once_t onceTokenSemaphore; \ 11 | dispatch_once(&onceTokenSemaphore, ^{ \ 12 | signalSemaphore = dispatch_semaphore_create(1); \ 13 | }); 14 | 15 | #define MJExtensionSemaphoreWait \ 16 | dispatch_semaphore_wait(signalSemaphore, DISPATCH_TIME_FOREVER); 17 | 18 | #define MJExtensionSemaphoreSignal \ 19 | dispatch_semaphore_signal(signalSemaphore); 20 | 21 | // 过期 22 | #define MJExtensionDeprecated(instead) NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead) 23 | 24 | // 构建错误 25 | #define MJExtensionBuildError(clazz, msg) \ 26 | NSError *error = [NSError errorWithDomain:msg code:250 userInfo:nil]; \ 27 | [clazz setMj_error:error]; 28 | 29 | // 日志输出 30 | #ifdef DEBUG 31 | #define MJExtensionLog(...) NSLog(__VA_ARGS__) 32 | #else 33 | #define MJExtensionLog(...) 34 | #endif 35 | 36 | /** 37 | * 断言 38 | * @param condition 条件 39 | * @param returnValue 返回值 40 | */ 41 | #define MJExtensionAssertError(condition, returnValue, clazz, msg) \ 42 | [clazz setMj_error:nil]; \ 43 | if ((condition) == NO) { \ 44 | MJExtensionBuildError(clazz, msg); \ 45 | return returnValue;\ 46 | } 47 | 48 | #define MJExtensionAssert2(condition, returnValue) \ 49 | if ((condition) == NO) return returnValue; 50 | 51 | /** 52 | * 断言 53 | * @param condition 条件 54 | */ 55 | #define MJExtensionAssert(condition) MJExtensionAssert2(condition, ) 56 | 57 | /** 58 | * 断言 59 | * @param param 参数 60 | * @param returnValue 返回值 61 | */ 62 | #define MJExtensionAssertParamNotNil2(param, returnValue) \ 63 | MJExtensionAssert2((param) != nil, returnValue) 64 | 65 | /** 66 | * 断言 67 | * @param param 参数 68 | */ 69 | #define MJExtensionAssertParamNotNil(param) MJExtensionAssertParamNotNil2(param, ) 70 | 71 | /** 72 | * 打印所有的属性 73 | */ 74 | #define MJLogAllIvars \ 75 | -(NSString *)description \ 76 | { \ 77 | return [self mj_keyValues].description; \ 78 | } 79 | #define MJExtensionLogAllProperties MJLogAllIvars 80 | 81 | /** 82 | * 类型(属性类型) 83 | */ 84 | extern NSString *const MJPropertyTypeInt; 85 | extern NSString *const MJPropertyTypeShort; 86 | extern NSString *const MJPropertyTypeFloat; 87 | extern NSString *const MJPropertyTypeDouble; 88 | extern NSString *const MJPropertyTypeLong; 89 | extern NSString *const MJPropertyTypeLongLong; 90 | extern NSString *const MJPropertyTypeChar; 91 | extern NSString *const MJPropertyTypeBOOL1; 92 | extern NSString *const MJPropertyTypeBOOL2; 93 | extern NSString *const MJPropertyTypePointer; 94 | 95 | extern NSString *const MJPropertyTypeIvar; 96 | extern NSString *const MJPropertyTypeMethod; 97 | extern NSString *const MJPropertyTypeBlock; 98 | extern NSString *const MJPropertyTypeClass; 99 | extern NSString *const MJPropertyTypeSEL; 100 | extern NSString *const MJPropertyTypeId; 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /Pods/MJExtension/MJExtension/MJExtensionConst.m: -------------------------------------------------------------------------------- 1 | #ifndef __MJExtensionConst__M__ 2 | #define __MJExtensionConst__M__ 3 | 4 | #import 5 | 6 | /** 7 | * 成员变量类型(属性类型) 8 | */ 9 | NSString *const MJPropertyTypeInt = @"i"; 10 | NSString *const MJPropertyTypeShort = @"s"; 11 | NSString *const MJPropertyTypeFloat = @"f"; 12 | NSString *const MJPropertyTypeDouble = @"d"; 13 | NSString *const MJPropertyTypeLong = @"l"; 14 | NSString *const MJPropertyTypeLongLong = @"q"; 15 | NSString *const MJPropertyTypeChar = @"c"; 16 | NSString *const MJPropertyTypeBOOL1 = @"c"; 17 | NSString *const MJPropertyTypeBOOL2 = @"b"; 18 | NSString *const MJPropertyTypePointer = @"*"; 19 | 20 | NSString *const MJPropertyTypeIvar = @"^{objc_ivar=}"; 21 | NSString *const MJPropertyTypeMethod = @"^{objc_method=}"; 22 | NSString *const MJPropertyTypeBlock = @"@?"; 23 | NSString *const MJPropertyTypeClass = @"#"; 24 | NSString *const MJPropertyTypeSEL = @":"; 25 | NSString *const MJPropertyTypeId = @"@"; 26 | 27 | #endif -------------------------------------------------------------------------------- /Pods/MJExtension/MJExtension/MJFoundation.h: -------------------------------------------------------------------------------- 1 | // 2 | // MJFoundation.h 3 | // MJExtensionExample 4 | // 5 | // Created by MJ Lee on 14/7/16. 6 | // Copyright (c) 2014年 小码哥. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MJFoundation : NSObject 12 | + (BOOL)isClassFromFoundation:(Class)c; 13 | @end 14 | -------------------------------------------------------------------------------- /Pods/MJExtension/MJExtension/MJFoundation.m: -------------------------------------------------------------------------------- 1 | // 2 | // MJFoundation.m 3 | // MJExtensionExample 4 | // 5 | // Created by MJ Lee on 14/7/16. 6 | // Copyright (c) 2014年 小码哥. All rights reserved. 7 | // 8 | 9 | #import "MJFoundation.h" 10 | #import "MJExtensionConst.h" 11 | #import 12 | 13 | @implementation MJFoundation 14 | 15 | + (BOOL)isClassFromFoundation:(Class)c 16 | { 17 | if (c == [NSObject class] || c == [NSManagedObject class]) return YES; 18 | 19 | static NSSet *foundationClasses; 20 | static dispatch_once_t onceToken; 21 | dispatch_once(&onceToken, ^{ 22 | // 集合中没有NSObject,因为几乎所有的类都是继承自NSObject,具体是不是NSObject需要特殊判断 23 | foundationClasses = [NSSet setWithObjects: 24 | [NSURL class], 25 | [NSDate class], 26 | [NSValue class], 27 | [NSData class], 28 | [NSError class], 29 | [NSArray class], 30 | [NSDictionary class], 31 | [NSString class], 32 | [NSAttributedString class], nil]; 33 | }); 34 | 35 | __block BOOL result = NO; 36 | [foundationClasses enumerateObjectsUsingBlock:^(Class foundationClass, BOOL *stop) { 37 | if ([c isSubclassOfClass:foundationClass]) { 38 | result = YES; 39 | *stop = YES; 40 | } 41 | }]; 42 | return result; 43 | } 44 | @end 45 | -------------------------------------------------------------------------------- /Pods/MJExtension/MJExtension/MJProperty.h: -------------------------------------------------------------------------------- 1 | // 2 | // MJProperty.h 3 | // MJExtensionExample 4 | // 5 | // Created by MJ Lee on 15/4/17. 6 | // Copyright (c) 2015年 小码哥. All rights reserved. 7 | // 包装一个成员属性 8 | 9 | #import 10 | #import 11 | #import "MJPropertyType.h" 12 | #import "MJPropertyKey.h" 13 | 14 | /** 15 | * 包装一个成员 16 | */ 17 | @interface MJProperty : NSObject 18 | /** 成员属性 */ 19 | @property (nonatomic, assign) objc_property_t property; 20 | /** 成员属性的名字 */ 21 | @property (nonatomic, readonly) NSString *name; 22 | 23 | /** 成员属性的类型 */ 24 | @property (nonatomic, readonly) MJPropertyType *type; 25 | /** 成员属性来源于哪个类(可能是父类) */ 26 | @property (nonatomic, assign) Class srcClass; 27 | 28 | /**** 同一个成员属性 - 父类和子类的行为可能不一致(originKey、propertyKeys、objectClassInArray) ****/ 29 | /** 设置最原始的key */ 30 | - (void)setOriginKey:(id)originKey forClass:(Class)c; 31 | /** 对应着字典中的多级key(里面存放的数组,数组里面都是MJPropertyKey对象) */ 32 | - (NSArray *)propertyKeysForClass:(Class)c; 33 | 34 | /** 模型数组中的模型类型 */ 35 | - (void)setObjectClassInArray:(Class)objectClass forClass:(Class)c; 36 | - (Class)objectClassInArrayForClass:(Class)c; 37 | /**** 同一个成员变量 - 父类和子类的行为可能不一致(key、keys、objectClassInArray) ****/ 38 | 39 | /** 40 | * 设置object的成员变量值 41 | */ 42 | - (void)setValue:(id)value forObject:(id)object; 43 | /** 44 | * 得到object的成员属性值 45 | */ 46 | - (id)valueForObject:(id)object; 47 | 48 | /** 49 | * 初始化 50 | */ 51 | + (instancetype)cachedPropertyWithProperty:(objc_property_t)property; 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /Pods/MJExtension/MJExtension/MJProperty.m: -------------------------------------------------------------------------------- 1 | // 2 | // MJProperty.m 3 | // MJExtensionExample 4 | // 5 | // Created by MJ Lee on 15/4/17. 6 | // Copyright (c) 2015年 小码哥. All rights reserved. 7 | // 8 | 9 | #import "MJProperty.h" 10 | #import "MJFoundation.h" 11 | #import "MJExtensionConst.h" 12 | #import 13 | 14 | @interface MJProperty() 15 | @property (strong, nonatomic) NSMutableDictionary *propertyKeysDict; 16 | @property (strong, nonatomic) NSMutableDictionary *objectClassInArrayDict; 17 | @end 18 | 19 | @implementation MJProperty 20 | 21 | #pragma mark - 初始化 22 | - (instancetype)init 23 | { 24 | if (self = [super init]) { 25 | _propertyKeysDict = [NSMutableDictionary dictionary]; 26 | _objectClassInArrayDict = [NSMutableDictionary dictionary]; 27 | } 28 | return self; 29 | } 30 | 31 | #pragma mark - 缓存 32 | + (instancetype)cachedPropertyWithProperty:(objc_property_t)property 33 | { 34 | MJExtensionSemaphoreCreate 35 | MJExtensionSemaphoreWait 36 | MJProperty *propertyObj = objc_getAssociatedObject(self, property); 37 | if (propertyObj == nil) { 38 | propertyObj = [[self alloc] init]; 39 | propertyObj.property = property; 40 | objc_setAssociatedObject(self, property, propertyObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 41 | } 42 | MJExtensionSemaphoreSignal 43 | return propertyObj; 44 | } 45 | 46 | #pragma mark - 公共方法 47 | - (void)setProperty:(objc_property_t)property 48 | { 49 | _property = property; 50 | 51 | MJExtensionAssertParamNotNil(property); 52 | 53 | // 1.属性名 54 | _name = @(property_getName(property)); 55 | 56 | // 2.成员类型 57 | NSString *attrs = @(property_getAttributes(property)); 58 | NSUInteger dotLoc = [attrs rangeOfString:@","].location; 59 | NSString *code = nil; 60 | NSUInteger loc = 1; 61 | if (dotLoc == NSNotFound) { // 没有, 62 | code = [attrs substringFromIndex:loc]; 63 | } else { 64 | code = [attrs substringWithRange:NSMakeRange(loc, dotLoc - loc)]; 65 | } 66 | _type = [MJPropertyType cachedTypeWithCode:code]; 67 | } 68 | 69 | /** 70 | * 获得成员变量的值 71 | */ 72 | - (id)valueForObject:(id)object 73 | { 74 | if (self.type.KVCDisabled) return [NSNull null]; 75 | return [object valueForKey:self.name]; 76 | } 77 | 78 | /** 79 | * 设置成员变量的值 80 | */ 81 | - (void)setValue:(id)value forObject:(id)object 82 | { 83 | if (self.type.KVCDisabled || value == nil) return; 84 | [object setValue:value forKey:self.name]; 85 | } 86 | 87 | /** 88 | * 通过字符串key创建对应的keys 89 | */ 90 | - (NSArray *)propertyKeysWithStringKey:(NSString *)stringKey 91 | { 92 | if (stringKey.length == 0) return nil; 93 | 94 | NSMutableArray *propertyKeys = [NSMutableArray array]; 95 | // 如果有多级映射 96 | NSArray *oldKeys = [stringKey componentsSeparatedByString:@"."]; 97 | 98 | for (NSString *oldKey in oldKeys) { 99 | NSUInteger start = [oldKey rangeOfString:@"["].location; 100 | if (start != NSNotFound) { // 有索引的key 101 | NSString *prefixKey = [oldKey substringToIndex:start]; 102 | NSString *indexKey = prefixKey; 103 | if (prefixKey.length) { 104 | MJPropertyKey *propertyKey = [[MJPropertyKey alloc] init]; 105 | propertyKey.name = prefixKey; 106 | [propertyKeys addObject:propertyKey]; 107 | 108 | indexKey = [oldKey stringByReplacingOccurrencesOfString:prefixKey withString:@""]; 109 | } 110 | 111 | /** 解析索引 **/ 112 | // 元素 113 | NSArray *cmps = [[indexKey stringByReplacingOccurrencesOfString:@"[" withString:@""] componentsSeparatedByString:@"]"]; 114 | for (NSInteger i = 0; i 10 | 11 | typedef enum { 12 | MJPropertyKeyTypeDictionary = 0, // 字典的key 13 | MJPropertyKeyTypeArray // 数组的key 14 | } MJPropertyKeyType; 15 | 16 | /** 17 | * 属性的key 18 | */ 19 | @interface MJPropertyKey : NSObject 20 | /** key的名字 */ 21 | @property (copy, nonatomic) NSString *name; 22 | /** key的种类,可能是@"10",可能是@"age" */ 23 | @property (assign, nonatomic) MJPropertyKeyType type; 24 | 25 | /** 26 | * 根据当前的key,也就是name,从object(字典或者数组)中取值 27 | */ 28 | - (id)valueInObject:(id)object; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Pods/MJExtension/MJExtension/MJPropertyKey.m: -------------------------------------------------------------------------------- 1 | // 2 | // MJPropertyKey.m 3 | // MJExtensionExample 4 | // 5 | // Created by MJ Lee on 15/8/11. 6 | // Copyright (c) 2015年 小码哥. All rights reserved. 7 | // 8 | 9 | #import "MJPropertyKey.h" 10 | 11 | @implementation MJPropertyKey 12 | 13 | - (id)valueInObject:(id)object 14 | { 15 | if ([object isKindOfClass:[NSDictionary class]] && self.type == MJPropertyKeyTypeDictionary) { 16 | return object[self.name]; 17 | } else if ([object isKindOfClass:[NSArray class]] && self.type == MJPropertyKeyTypeArray) { 18 | NSArray *array = object; 19 | NSUInteger index = self.name.intValue; 20 | if (index < array.count) return array[index]; 21 | return nil; 22 | } 23 | return nil; 24 | } 25 | @end 26 | -------------------------------------------------------------------------------- /Pods/MJExtension/MJExtension/MJPropertyType.h: -------------------------------------------------------------------------------- 1 | // 2 | // MJPropertyType.h 3 | // MJExtension 4 | // 5 | // Created by mj on 14-1-15. 6 | // Copyright (c) 2014年 小码哥. All rights reserved. 7 | // 包装一种类型 8 | 9 | #import 10 | 11 | /** 12 | * 包装一种类型 13 | */ 14 | @interface MJPropertyType : NSObject 15 | /** 类型标识符 */ 16 | @property (nonatomic, copy) NSString *code; 17 | 18 | /** 是否为id类型 */ 19 | @property (nonatomic, readonly, getter=isIdType) BOOL idType; 20 | 21 | /** 是否为基本数字类型:int、float等 */ 22 | @property (nonatomic, readonly, getter=isNumberType) BOOL numberType; 23 | 24 | /** 是否为BOOL类型 */ 25 | @property (nonatomic, readonly, getter=isBoolType) BOOL boolType; 26 | 27 | /** 对象类型(如果是基本数据类型,此值为nil) */ 28 | @property (nonatomic, readonly) Class typeClass; 29 | 30 | /** 类型是否来自于Foundation框架,比如NSString、NSArray */ 31 | @property (nonatomic, readonly, getter = isFromFoundation) BOOL fromFoundation; 32 | /** 类型是否不支持KVC */ 33 | @property (nonatomic, readonly, getter = isKVCDisabled) BOOL KVCDisabled; 34 | 35 | /** 36 | * 获得缓存的类型对象 37 | */ 38 | + (instancetype)cachedTypeWithCode:(NSString *)code; 39 | @end -------------------------------------------------------------------------------- /Pods/MJExtension/MJExtension/MJPropertyType.m: -------------------------------------------------------------------------------- 1 | // 2 | // MJPropertyType.m 3 | // MJExtension 4 | // 5 | // Created by mj on 14-1-15. 6 | // Copyright (c) 2014年 小码哥. All rights reserved. 7 | // 8 | 9 | #import "MJPropertyType.h" 10 | #import "MJExtension.h" 11 | #import "MJFoundation.h" 12 | #import "MJExtensionConst.h" 13 | 14 | @implementation MJPropertyType 15 | 16 | + (instancetype)cachedTypeWithCode:(NSString *)code 17 | { 18 | MJExtensionAssertParamNotNil2(code, nil); 19 | 20 | static NSMutableDictionary *types; 21 | static dispatch_once_t onceToken; 22 | dispatch_once(&onceToken, ^{ 23 | types = [NSMutableDictionary dictionary]; 24 | }); 25 | 26 | MJExtensionSemaphoreCreate 27 | MJExtensionSemaphoreWait 28 | MJPropertyType *type = types[code]; 29 | if (type == nil) { 30 | type = [[self alloc] init]; 31 | type.code = code; 32 | types[code] = type; 33 | } 34 | MJExtensionSemaphoreSignal 35 | return type; 36 | } 37 | 38 | #pragma mark - 公共方法 39 | - (void)setCode:(NSString *)code 40 | { 41 | _code = code; 42 | 43 | MJExtensionAssertParamNotNil(code); 44 | 45 | if ([code isEqualToString:MJPropertyTypeId]) { 46 | _idType = YES; 47 | } else if (code.length == 0) { 48 | _KVCDisabled = YES; 49 | } else if (code.length > 3 && [code hasPrefix:@"@\""]) { 50 | // 去掉@"和",截取中间的类型名称 51 | _code = [code substringWithRange:NSMakeRange(2, code.length - 3)]; 52 | _typeClass = NSClassFromString(_code); 53 | _fromFoundation = [MJFoundation isClassFromFoundation:_typeClass]; 54 | _numberType = [_typeClass isSubclassOfClass:[NSNumber class]]; 55 | 56 | } else if ([code isEqualToString:MJPropertyTypeSEL] || 57 | [code isEqualToString:MJPropertyTypeIvar] || 58 | [code isEqualToString:MJPropertyTypeMethod]) { 59 | _KVCDisabled = YES; 60 | } 61 | 62 | // 是否为数字类型 63 | NSString *lowerCode = _code.lowercaseString; 64 | NSArray *numberTypes = @[MJPropertyTypeInt, MJPropertyTypeShort, MJPropertyTypeBOOL1, MJPropertyTypeBOOL2, MJPropertyTypeFloat, MJPropertyTypeDouble, MJPropertyTypeLong, MJPropertyTypeLongLong, MJPropertyTypeChar]; 65 | if ([numberTypes containsObject:lowerCode]) { 66 | _numberType = YES; 67 | 68 | if ([lowerCode isEqualToString:MJPropertyTypeBOOL1] 69 | || [lowerCode isEqualToString:MJPropertyTypeBOOL2]) { 70 | _boolType = YES; 71 | } 72 | } 73 | } 74 | @end 75 | -------------------------------------------------------------------------------- /Pods/MJExtension/MJExtension/NSObject+MJClass.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+MJClass.h 3 | // MJExtensionExample 4 | // 5 | // Created by MJ Lee on 15/8/11. 6 | // Copyright (c) 2015年 小码哥. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * 遍历所有类的block(父类) 13 | */ 14 | typedef void (^MJClassesEnumeration)(Class c, BOOL *stop); 15 | 16 | /** 这个数组中的属性名才会进行字典和模型的转换 */ 17 | typedef NSArray * (^MJAllowedPropertyNames)(void); 18 | /** 这个数组中的属性名才会进行归档 */ 19 | typedef NSArray * (^MJAllowedCodingPropertyNames)(void); 20 | 21 | /** 这个数组中的属性名将会被忽略:不进行字典和模型的转换 */ 22 | typedef NSArray * (^MJIgnoredPropertyNames)(void); 23 | /** 这个数组中的属性名将会被忽略:不进行归档 */ 24 | typedef NSArray * (^MJIgnoredCodingPropertyNames)(void); 25 | 26 | /** 27 | * 类相关的扩展 28 | */ 29 | @interface NSObject (MJClass) 30 | /** 31 | * 遍历所有的类 32 | */ 33 | + (void)mj_enumerateClasses:(MJClassesEnumeration)enumeration; 34 | + (void)mj_enumerateAllClasses:(MJClassesEnumeration)enumeration; 35 | 36 | #pragma mark - 属性白名单配置 37 | /** 38 | * 这个数组中的属性名才会进行字典和模型的转换 39 | * 40 | * @param allowedPropertyNames 这个数组中的属性名才会进行字典和模型的转换 41 | */ 42 | + (void)mj_setupAllowedPropertyNames:(MJAllowedPropertyNames)allowedPropertyNames; 43 | 44 | /** 45 | * 这个数组中的属性名才会进行字典和模型的转换 46 | */ 47 | + (NSMutableArray *)mj_totalAllowedPropertyNames; 48 | 49 | #pragma mark - 属性黑名单配置 50 | /** 51 | * 这个数组中的属性名将会被忽略:不进行字典和模型的转换 52 | * 53 | * @param ignoredPropertyNames 这个数组中的属性名将会被忽略:不进行字典和模型的转换 54 | */ 55 | + (void)mj_setupIgnoredPropertyNames:(MJIgnoredPropertyNames)ignoredPropertyNames; 56 | 57 | /** 58 | * 这个数组中的属性名将会被忽略:不进行字典和模型的转换 59 | */ 60 | + (NSMutableArray *)mj_totalIgnoredPropertyNames; 61 | 62 | #pragma mark - 归档属性白名单配置 63 | /** 64 | * 这个数组中的属性名才会进行归档 65 | * 66 | * @param allowedCodingPropertyNames 这个数组中的属性名才会进行归档 67 | */ 68 | + (void)mj_setupAllowedCodingPropertyNames:(MJAllowedCodingPropertyNames)allowedCodingPropertyNames; 69 | 70 | /** 71 | * 这个数组中的属性名才会进行字典和模型的转换 72 | */ 73 | + (NSMutableArray *)mj_totalAllowedCodingPropertyNames; 74 | 75 | #pragma mark - 归档属性黑名单配置 76 | /** 77 | * 这个数组中的属性名将会被忽略:不进行归档 78 | * 79 | * @param ignoredCodingPropertyNames 这个数组中的属性名将会被忽略:不进行归档 80 | */ 81 | + (void)mj_setupIgnoredCodingPropertyNames:(MJIgnoredCodingPropertyNames)ignoredCodingPropertyNames; 82 | 83 | /** 84 | * 这个数组中的属性名将会被忽略:不进行归档 85 | */ 86 | + (NSMutableArray *)mj_totalIgnoredCodingPropertyNames; 87 | 88 | #pragma mark - 内部使用 89 | + (void)mj_setupBlockReturnValue:(id (^)(void))block key:(const char *)key; 90 | @end 91 | -------------------------------------------------------------------------------- /Pods/MJExtension/MJExtension/NSObject+MJClass.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+MJClass.m 3 | // MJExtensionExample 4 | // 5 | // Created by MJ Lee on 15/8/11. 6 | // Copyright (c) 2015年 小码哥. All rights reserved. 7 | // 8 | 9 | #import "NSObject+MJClass.h" 10 | #import "NSObject+MJCoding.h" 11 | #import "NSObject+MJKeyValue.h" 12 | #import "MJFoundation.h" 13 | #import 14 | 15 | static const char MJAllowedPropertyNamesKey = '\0'; 16 | static const char MJIgnoredPropertyNamesKey = '\0'; 17 | static const char MJAllowedCodingPropertyNamesKey = '\0'; 18 | static const char MJIgnoredCodingPropertyNamesKey = '\0'; 19 | 20 | @implementation NSObject (MJClass) 21 | 22 | + (NSMutableDictionary *)classDictForKey:(const void *)key 23 | { 24 | static NSMutableDictionary *allowedPropertyNamesDict; 25 | static NSMutableDictionary *ignoredPropertyNamesDict; 26 | static NSMutableDictionary *allowedCodingPropertyNamesDict; 27 | static NSMutableDictionary *ignoredCodingPropertyNamesDict; 28 | 29 | static dispatch_once_t onceToken; 30 | dispatch_once(&onceToken, ^{ 31 | allowedPropertyNamesDict = [NSMutableDictionary dictionary]; 32 | ignoredPropertyNamesDict = [NSMutableDictionary dictionary]; 33 | allowedCodingPropertyNamesDict = [NSMutableDictionary dictionary]; 34 | ignoredCodingPropertyNamesDict = [NSMutableDictionary dictionary]; 35 | }); 36 | 37 | if (key == &MJAllowedPropertyNamesKey) return allowedPropertyNamesDict; 38 | if (key == &MJIgnoredPropertyNamesKey) return ignoredPropertyNamesDict; 39 | if (key == &MJAllowedCodingPropertyNamesKey) return allowedCodingPropertyNamesDict; 40 | if (key == &MJIgnoredCodingPropertyNamesKey) return ignoredCodingPropertyNamesDict; 41 | return nil; 42 | } 43 | 44 | + (void)mj_enumerateClasses:(MJClassesEnumeration)enumeration 45 | { 46 | // 1.没有block就直接返回 47 | if (enumeration == nil) return; 48 | 49 | // 2.停止遍历的标记 50 | BOOL stop = NO; 51 | 52 | // 3.当前正在遍历的类 53 | Class c = self; 54 | 55 | // 4.开始遍历每一个类 56 | while (c && !stop) { 57 | // 4.1.执行操作 58 | enumeration(c, &stop); 59 | 60 | // 4.2.获得父类 61 | c = class_getSuperclass(c); 62 | 63 | if ([MJFoundation isClassFromFoundation:c]) break; 64 | } 65 | } 66 | 67 | + (void)mj_enumerateAllClasses:(MJClassesEnumeration)enumeration 68 | { 69 | // 1.没有block就直接返回 70 | if (enumeration == nil) return; 71 | 72 | // 2.停止遍历的标记 73 | BOOL stop = NO; 74 | 75 | // 3.当前正在遍历的类 76 | Class c = self; 77 | 78 | // 4.开始遍历每一个类 79 | while (c && !stop) { 80 | // 4.1.执行操作 81 | enumeration(c, &stop); 82 | 83 | // 4.2.获得父类 84 | c = class_getSuperclass(c); 85 | } 86 | } 87 | 88 | #pragma mark - 属性黑名单配置 89 | + (void)mj_setupIgnoredPropertyNames:(MJIgnoredPropertyNames)ignoredPropertyNames 90 | { 91 | [self mj_setupBlockReturnValue:ignoredPropertyNames key:&MJIgnoredPropertyNamesKey]; 92 | } 93 | 94 | + (NSMutableArray *)mj_totalIgnoredPropertyNames 95 | { 96 | return [self mj_totalObjectsWithSelector:@selector(mj_ignoredPropertyNames) key:&MJIgnoredPropertyNamesKey]; 97 | } 98 | 99 | #pragma mark - 归档属性黑名单配置 100 | + (void)mj_setupIgnoredCodingPropertyNames:(MJIgnoredCodingPropertyNames)ignoredCodingPropertyNames 101 | { 102 | [self mj_setupBlockReturnValue:ignoredCodingPropertyNames key:&MJIgnoredCodingPropertyNamesKey]; 103 | } 104 | 105 | + (NSMutableArray *)mj_totalIgnoredCodingPropertyNames 106 | { 107 | return [self mj_totalObjectsWithSelector:@selector(mj_ignoredCodingPropertyNames) key:&MJIgnoredCodingPropertyNamesKey]; 108 | } 109 | 110 | #pragma mark - 属性白名单配置 111 | + (void)mj_setupAllowedPropertyNames:(MJAllowedPropertyNames)allowedPropertyNames; 112 | { 113 | [self mj_setupBlockReturnValue:allowedPropertyNames key:&MJAllowedPropertyNamesKey]; 114 | } 115 | 116 | + (NSMutableArray *)mj_totalAllowedPropertyNames 117 | { 118 | return [self mj_totalObjectsWithSelector:@selector(mj_allowedPropertyNames) key:&MJAllowedPropertyNamesKey]; 119 | } 120 | 121 | #pragma mark - 归档属性白名单配置 122 | + (void)mj_setupAllowedCodingPropertyNames:(MJAllowedCodingPropertyNames)allowedCodingPropertyNames 123 | { 124 | [self mj_setupBlockReturnValue:allowedCodingPropertyNames key:&MJAllowedCodingPropertyNamesKey]; 125 | } 126 | 127 | + (NSMutableArray *)mj_totalAllowedCodingPropertyNames 128 | { 129 | return [self mj_totalObjectsWithSelector:@selector(mj_allowedCodingPropertyNames) key:&MJAllowedCodingPropertyNamesKey]; 130 | } 131 | 132 | #pragma mark - block和方法处理:存储block的返回值 133 | + (void)mj_setupBlockReturnValue:(id (^)(void))block key:(const char *)key 134 | { 135 | if (block) { 136 | objc_setAssociatedObject(self, key, block(), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 137 | } else { 138 | objc_setAssociatedObject(self, key, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 139 | } 140 | 141 | // 清空数据 142 | MJExtensionSemaphoreCreate 143 | MJExtensionSemaphoreWait 144 | [[self classDictForKey:key] removeAllObjects]; 145 | MJExtensionSemaphoreSignal 146 | } 147 | 148 | + (NSMutableArray *)mj_totalObjectsWithSelector:(SEL)selector key:(const char *)key 149 | { 150 | MJExtensionSemaphoreCreate 151 | MJExtensionSemaphoreWait 152 | 153 | NSMutableArray *array = [self classDictForKey:key][NSStringFromClass(self)]; 154 | if (array == nil) { 155 | // 创建、存储 156 | [self classDictForKey:key][NSStringFromClass(self)] = array = [NSMutableArray array]; 157 | 158 | if ([self respondsToSelector:selector]) { 159 | #pragma clang diagnostic push 160 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" 161 | NSArray *subArray = [self performSelector:selector]; 162 | #pragma clang diagnostic pop 163 | if (subArray) { 164 | [array addObjectsFromArray:subArray]; 165 | } 166 | } 167 | 168 | [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) { 169 | NSArray *subArray = objc_getAssociatedObject(c, key); 170 | [array addObjectsFromArray:subArray]; 171 | }]; 172 | } 173 | 174 | MJExtensionSemaphoreSignal 175 | 176 | return array; 177 | } 178 | @end 179 | -------------------------------------------------------------------------------- /Pods/MJExtension/MJExtension/NSObject+MJCoding.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+MJCoding.h 3 | // MJExtension 4 | // 5 | // Created by mj on 14-1-15. 6 | // Copyright (c) 2014年 小码哥. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MJExtensionConst.h" 11 | 12 | /** 13 | * Codeing协议 14 | */ 15 | @protocol MJCoding 16 | @optional 17 | /** 18 | * 这个数组中的属性名才会进行归档 19 | */ 20 | + (NSArray *)mj_allowedCodingPropertyNames; 21 | /** 22 | * 这个数组中的属性名将会被忽略:不进行归档 23 | */ 24 | + (NSArray *)mj_ignoredCodingPropertyNames; 25 | @end 26 | 27 | @interface NSObject (MJCoding) 28 | /** 29 | * 解码(从文件中解析对象) 30 | */ 31 | - (void)mj_decode:(NSCoder *)decoder; 32 | /** 33 | * 编码(将对象写入文件中) 34 | */ 35 | - (void)mj_encode:(NSCoder *)encoder; 36 | @end 37 | 38 | /** 39 | 归档的实现 40 | */ 41 | #define MJCodingImplementation \ 42 | - (id)initWithCoder:(NSCoder *)decoder \ 43 | { \ 44 | if (self = [super init]) { \ 45 | [self mj_decode:decoder]; \ 46 | } \ 47 | return self; \ 48 | } \ 49 | \ 50 | - (void)encodeWithCoder:(NSCoder *)encoder \ 51 | { \ 52 | [self mj_encode:encoder]; \ 53 | } 54 | 55 | #define MJExtensionCodingImplementation MJCodingImplementation -------------------------------------------------------------------------------- /Pods/MJExtension/MJExtension/NSObject+MJCoding.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+MJCoding.m 3 | // MJExtension 4 | // 5 | // Created by mj on 14-1-15. 6 | // Copyright (c) 2014年 小码哥. All rights reserved. 7 | // 8 | 9 | #import "NSObject+MJCoding.h" 10 | #import "NSObject+MJClass.h" 11 | #import "NSObject+MJProperty.h" 12 | #import "MJProperty.h" 13 | 14 | @implementation NSObject (MJCoding) 15 | 16 | - (void)mj_encode:(NSCoder *)encoder 17 | { 18 | Class clazz = [self class]; 19 | 20 | NSArray *allowedCodingPropertyNames = [clazz mj_totalAllowedCodingPropertyNames]; 21 | NSArray *ignoredCodingPropertyNames = [clazz mj_totalIgnoredCodingPropertyNames]; 22 | 23 | [clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) { 24 | // 检测是否被忽略 25 | if (allowedCodingPropertyNames.count && ![allowedCodingPropertyNames containsObject:property.name]) return; 26 | if ([ignoredCodingPropertyNames containsObject:property.name]) return; 27 | 28 | id value = [property valueForObject:self]; 29 | if (value == nil) return; 30 | [encoder encodeObject:value forKey:property.name]; 31 | }]; 32 | } 33 | 34 | - (void)mj_decode:(NSCoder *)decoder 35 | { 36 | Class clazz = [self class]; 37 | 38 | NSArray *allowedCodingPropertyNames = [clazz mj_totalAllowedCodingPropertyNames]; 39 | NSArray *ignoredCodingPropertyNames = [clazz mj_totalIgnoredCodingPropertyNames]; 40 | 41 | [clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) { 42 | // 检测是否被忽略 43 | if (allowedCodingPropertyNames.count && ![allowedCodingPropertyNames containsObject:property.name]) return; 44 | if ([ignoredCodingPropertyNames containsObject:property.name]) return; 45 | 46 | id value = [decoder decodeObjectForKey:property.name]; 47 | if (value == nil) { // 兼容以前的MJExtension版本 48 | value = [decoder decodeObjectForKey:[@"_" stringByAppendingString:property.name]]; 49 | } 50 | if (value == nil) return; 51 | [property setValue:value forObject:self]; 52 | }]; 53 | } 54 | @end 55 | -------------------------------------------------------------------------------- /Pods/MJExtension/MJExtension/NSObject+MJKeyValue.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+MJKeyValue.h 3 | // MJExtension 4 | // 5 | // Created by mj on 13-8-24. 6 | // Copyright (c) 2013年 小码哥. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MJExtensionConst.h" 11 | #import 12 | #import "MJProperty.h" 13 | 14 | /** 15 | * KeyValue协议 16 | */ 17 | @protocol MJKeyValue 18 | @optional 19 | /** 20 | * 只有这个数组中的属性名才允许进行字典和模型的转换 21 | */ 22 | + (NSArray *)mj_allowedPropertyNames; 23 | 24 | /** 25 | * 这个数组中的属性名将会被忽略:不进行字典和模型的转换 26 | */ 27 | + (NSArray *)mj_ignoredPropertyNames; 28 | 29 | /** 30 | * 将属性名换为其他key去字典中取值 31 | * 32 | * @return 字典中的key是属性名,value是从字典中取值用的key 33 | */ 34 | + (NSDictionary *)mj_replacedKeyFromPropertyName; 35 | 36 | /** 37 | * 将属性名换为其他key去字典中取值 38 | * 39 | * @return 从字典中取值用的key 40 | */ 41 | + (id)mj_replacedKeyFromPropertyName121:(NSString *)propertyName; 42 | 43 | /** 44 | * 数组中需要转换的模型类 45 | * 46 | * @return 字典中的key是数组属性名,value是数组中存放模型的Class(Class类型或者NSString类型) 47 | */ 48 | + (NSDictionary *)mj_objectClassInArray; 49 | 50 | /** 51 | * 旧值换新值,用于过滤字典中的值 52 | * 53 | * @param oldValue 旧值 54 | * 55 | * @return 新值 56 | */ 57 | - (id)mj_newValueFromOldValue:(id)oldValue property:(MJProperty *)property; 58 | 59 | /** 60 | * 当字典转模型完毕时调用 61 | */ 62 | - (void)mj_keyValuesDidFinishConvertingToObject; 63 | 64 | /** 65 | * 当模型转字典完毕时调用 66 | */ 67 | - (void)mj_objectDidFinishConvertingToKeyValues; 68 | @end 69 | 70 | @interface NSObject (MJKeyValue) 71 | #pragma mark - 类方法 72 | /** 73 | * 字典转模型过程中遇到的错误 74 | */ 75 | + (NSError *)mj_error; 76 | 77 | /** 78 | * 模型转字典时,字典的key是否参考replacedKeyFromPropertyName等方法(父类设置了,子类也会继承下来) 79 | */ 80 | + (void)mj_referenceReplacedKeyWhenCreatingKeyValues:(BOOL)reference; 81 | 82 | #pragma mark - 对象方法 83 | /** 84 | * 将字典的键值对转成模型属性 85 | * @param keyValues 字典(可以是NSDictionary、NSData、NSString) 86 | */ 87 | - (instancetype)mj_setKeyValues:(id)keyValues; 88 | 89 | /** 90 | * 将字典的键值对转成模型属性 91 | * @param keyValues 字典(可以是NSDictionary、NSData、NSString) 92 | * @param context CoreData上下文 93 | */ 94 | - (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context; 95 | 96 | /** 97 | * 将模型转成字典 98 | * @return 字典 99 | */ 100 | - (NSMutableDictionary *)mj_keyValues; 101 | - (NSMutableDictionary *)mj_keyValuesWithKeys:(NSArray *)keys; 102 | - (NSMutableDictionary *)mj_keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys; 103 | 104 | /** 105 | * 通过模型数组来创建一个字典数组 106 | * @param objectArray 模型数组 107 | * @return 字典数组 108 | */ 109 | + (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray; 110 | + (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys; 111 | + (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys; 112 | 113 | #pragma mark - 字典转模型 114 | /** 115 | * 通过字典来创建一个模型 116 | * @param keyValues 字典(可以是NSDictionary、NSData、NSString) 117 | * @return 新建的对象 118 | */ 119 | + (instancetype)mj_objectWithKeyValues:(id)keyValues; 120 | 121 | /** 122 | * 通过字典来创建一个CoreData模型 123 | * @param keyValues 字典(可以是NSDictionary、NSData、NSString) 124 | * @param context CoreData上下文 125 | * @return 新建的对象 126 | */ 127 | + (instancetype)mj_objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context; 128 | 129 | /** 130 | * 通过plist来创建一个模型 131 | * @param filename 文件名(仅限于mainBundle中的文件) 132 | * @return 新建的对象 133 | */ 134 | + (instancetype)mj_objectWithFilename:(NSString *)filename; 135 | 136 | /** 137 | * 通过plist来创建一个模型 138 | * @param file 文件全路径 139 | * @return 新建的对象 140 | */ 141 | + (instancetype)mj_objectWithFile:(NSString *)file; 142 | 143 | #pragma mark - 字典数组转模型数组 144 | /** 145 | * 通过字典数组来创建一个模型数组 146 | * @param keyValuesArray 字典数组(可以是NSDictionary、NSData、NSString) 147 | * @return 模型数组 148 | */ 149 | + (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(id)keyValuesArray; 150 | 151 | /** 152 | * 通过字典数组来创建一个模型数组 153 | * @param keyValuesArray 字典数组(可以是NSDictionary、NSData、NSString) 154 | * @param context CoreData上下文 155 | * @return 模型数组 156 | */ 157 | + (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context; 158 | 159 | /** 160 | * 通过plist来创建一个模型数组 161 | * @param filename 文件名(仅限于mainBundle中的文件) 162 | * @return 模型数组 163 | */ 164 | + (NSMutableArray *)mj_objectArrayWithFilename:(NSString *)filename; 165 | 166 | /** 167 | * 通过plist来创建一个模型数组 168 | * @param file 文件全路径 169 | * @return 模型数组 170 | */ 171 | + (NSMutableArray *)mj_objectArrayWithFile:(NSString *)file; 172 | 173 | #pragma mark - 转换为JSON 174 | /** 175 | * 转换为JSON Data 176 | */ 177 | - (NSData *)mj_JSONData; 178 | /** 179 | * 转换为字典或者数组 180 | */ 181 | - (id)mj_JSONObject; 182 | /** 183 | * 转换为JSON 字符串 184 | */ 185 | - (NSString *)mj_JSONString; 186 | @end 187 | 188 | @interface NSObject (MJKeyValueDeprecated_v_2_5_16) 189 | - (instancetype)setKeyValues:(id)keyValue MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 190 | - (instancetype)setKeyValues:(id)keyValues error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 191 | - (instancetype)setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 192 | - (instancetype)setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 193 | + (void)referenceReplacedKeyWhenCreatingKeyValues:(BOOL)reference MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 194 | - (NSMutableDictionary *)keyValues MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 195 | - (NSMutableDictionary *)keyValuesWithError:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 196 | - (NSMutableDictionary *)keyValuesWithKeys:(NSArray *)keys MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 197 | - (NSMutableDictionary *)keyValuesWithKeys:(NSArray *)keys error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 198 | - (NSMutableDictionary *)keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 199 | - (NSMutableDictionary *)keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 200 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 201 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 202 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 203 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 204 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 205 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 206 | + (instancetype)objectWithKeyValues:(id)keyValues MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 207 | + (instancetype)objectWithKeyValues:(id)keyValues error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 208 | + (instancetype)objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 209 | + (instancetype)objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 210 | + (instancetype)objectWithFilename:(NSString *)filename MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 211 | + (instancetype)objectWithFilename:(NSString *)filename error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 212 | + (instancetype)objectWithFile:(NSString *)file MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 213 | + (instancetype)objectWithFile:(NSString *)file error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 214 | + (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 215 | + (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 216 | + (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 217 | + (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 218 | + (NSMutableArray *)objectArrayWithFilename:(NSString *)filename MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 219 | + (NSMutableArray *)objectArrayWithFilename:(NSString *)filename error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 220 | + (NSMutableArray *)objectArrayWithFile:(NSString *)file MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 221 | + (NSMutableArray *)objectArrayWithFile:(NSString *)file error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 222 | - (NSData *)JSONData MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 223 | - (id)JSONObject MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 224 | - (NSString *)JSONString MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 225 | @end 226 | -------------------------------------------------------------------------------- /Pods/MJExtension/MJExtension/NSObject+MJProperty.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+MJProperty.h 3 | // MJExtensionExample 4 | // 5 | // Created by MJ Lee on 15/4/17. 6 | // Copyright (c) 2015年 小码哥. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MJExtensionConst.h" 11 | 12 | @class MJProperty; 13 | 14 | /** 15 | * 遍历成员变量用的block 16 | * 17 | * @param property 成员的包装对象 18 | * @param stop YES代表停止遍历,NO代表继续遍历 19 | */ 20 | typedef void (^MJPropertiesEnumeration)(MJProperty *property, BOOL *stop); 21 | 22 | /** 将属性名换为其他key去字典中取值 */ 23 | typedef NSDictionary * (^MJReplacedKeyFromPropertyName)(void); 24 | typedef id (^MJReplacedKeyFromPropertyName121)(NSString *propertyName); 25 | /** 数组中需要转换的模型类 */ 26 | typedef NSDictionary * (^MJObjectClassInArray)(void); 27 | /** 用于过滤字典中的值 */ 28 | typedef id (^MJNewValueFromOldValue)(id object, id oldValue, MJProperty *property); 29 | 30 | /** 31 | * 成员属性相关的扩展 32 | */ 33 | @interface NSObject (MJProperty) 34 | #pragma mark - 遍历 35 | /** 36 | * 遍历所有的成员 37 | */ 38 | + (void)mj_enumerateProperties:(MJPropertiesEnumeration)enumeration; 39 | 40 | #pragma mark - 新值配置 41 | /** 42 | * 用于过滤字典中的值 43 | * 44 | * @param newValueFormOldValue 用于过滤字典中的值 45 | */ 46 | + (void)mj_setupNewValueFromOldValue:(MJNewValueFromOldValue)newValueFormOldValue; 47 | + (id)mj_getNewValueFromObject:(__unsafe_unretained id)object oldValue:(__unsafe_unretained id)oldValue property:(__unsafe_unretained MJProperty *)property; 48 | 49 | #pragma mark - key配置 50 | /** 51 | * 将属性名换为其他key去字典中取值 52 | * 53 | * @param replacedKeyFromPropertyName 将属性名换为其他key去字典中取值 54 | */ 55 | + (void)mj_setupReplacedKeyFromPropertyName:(MJReplacedKeyFromPropertyName)replacedKeyFromPropertyName; 56 | /** 57 | * 将属性名换为其他key去字典中取值 58 | * 59 | * @param replacedKeyFromPropertyName121 将属性名换为其他key去字典中取值 60 | */ 61 | + (void)mj_setupReplacedKeyFromPropertyName121:(MJReplacedKeyFromPropertyName121)replacedKeyFromPropertyName121; 62 | 63 | #pragma mark - array model class配置 64 | /** 65 | * 数组中需要转换的模型类 66 | * 67 | * @param objectClassInArray 数组中需要转换的模型类 68 | */ 69 | + (void)mj_setupObjectClassInArray:(MJObjectClassInArray)objectClassInArray; 70 | @end 71 | 72 | @interface NSObject (MJPropertyDeprecated_v_2_5_16) 73 | + (void)enumerateProperties:(MJPropertiesEnumeration)enumeration MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 74 | + (void)setupNewValueFromOldValue:(MJNewValueFromOldValue)newValueFormOldValue MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 75 | + (id)getNewValueFromObject:(__unsafe_unretained id)object oldValue:(__unsafe_unretained id)oldValue property:(__unsafe_unretained MJProperty *)property MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 76 | + (void)setupReplacedKeyFromPropertyName:(MJReplacedKeyFromPropertyName)replacedKeyFromPropertyName MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 77 | + (void)setupReplacedKeyFromPropertyName121:(MJReplacedKeyFromPropertyName121)replacedKeyFromPropertyName121 MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 78 | + (void)setupObjectClassInArray:(MJObjectClassInArray)objectClassInArray MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 79 | @end 80 | -------------------------------------------------------------------------------- /Pods/MJExtension/MJExtension/NSObject+MJProperty.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+MJProperty.m 3 | // MJExtensionExample 4 | // 5 | // Created by MJ Lee on 15/4/17. 6 | // Copyright (c) 2015年 小码哥. All rights reserved. 7 | // 8 | 9 | #import "NSObject+MJProperty.h" 10 | #import "NSObject+MJKeyValue.h" 11 | #import "NSObject+MJCoding.h" 12 | #import "NSObject+MJClass.h" 13 | #import "MJProperty.h" 14 | #import "MJFoundation.h" 15 | #import 16 | 17 | #pragma clang diagnostic push 18 | #pragma clang diagnostic ignored "-Wundeclared-selector" 19 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" 20 | 21 | static const char MJReplacedKeyFromPropertyNameKey = '\0'; 22 | static const char MJReplacedKeyFromPropertyName121Key = '\0'; 23 | static const char MJNewValueFromOldValueKey = '\0'; 24 | static const char MJObjectClassInArrayKey = '\0'; 25 | 26 | static const char MJCachedPropertiesKey = '\0'; 27 | 28 | @implementation NSObject (Property) 29 | 30 | + (NSMutableDictionary *)propertyDictForKey:(const void *)key 31 | { 32 | static NSMutableDictionary *replacedKeyFromPropertyNameDict; 33 | static NSMutableDictionary *replacedKeyFromPropertyName121Dict; 34 | static NSMutableDictionary *newValueFromOldValueDict; 35 | static NSMutableDictionary *objectClassInArrayDict; 36 | static NSMutableDictionary *cachedPropertiesDict; 37 | 38 | static dispatch_once_t onceToken; 39 | dispatch_once(&onceToken, ^{ 40 | replacedKeyFromPropertyNameDict = [NSMutableDictionary dictionary]; 41 | replacedKeyFromPropertyName121Dict = [NSMutableDictionary dictionary]; 42 | newValueFromOldValueDict = [NSMutableDictionary dictionary]; 43 | objectClassInArrayDict = [NSMutableDictionary dictionary]; 44 | cachedPropertiesDict = [NSMutableDictionary dictionary]; 45 | }); 46 | 47 | if (key == &MJReplacedKeyFromPropertyNameKey) return replacedKeyFromPropertyNameDict; 48 | if (key == &MJReplacedKeyFromPropertyName121Key) return replacedKeyFromPropertyName121Dict; 49 | if (key == &MJNewValueFromOldValueKey) return newValueFromOldValueDict; 50 | if (key == &MJObjectClassInArrayKey) return objectClassInArrayDict; 51 | if (key == &MJCachedPropertiesKey) return cachedPropertiesDict; 52 | return nil; 53 | } 54 | 55 | #pragma mark - --私有方法-- 56 | + (id)propertyKey:(NSString *)propertyName 57 | { 58 | MJExtensionAssertParamNotNil2(propertyName, nil); 59 | 60 | __block id key = nil; 61 | // 查看有没有需要替换的key 62 | if ([self respondsToSelector:@selector(mj_replacedKeyFromPropertyName121:)]) { 63 | key = [self mj_replacedKeyFromPropertyName121:propertyName]; 64 | } 65 | // 兼容旧版本 66 | if ([self respondsToSelector:@selector(replacedKeyFromPropertyName121:)]) { 67 | key = [self performSelector:@selector(replacedKeyFromPropertyName121) withObject:propertyName]; 68 | } 69 | 70 | // 调用block 71 | if (!key) { 72 | [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) { 73 | MJReplacedKeyFromPropertyName121 block = objc_getAssociatedObject(c, &MJReplacedKeyFromPropertyName121Key); 74 | if (block) { 75 | key = block(propertyName); 76 | } 77 | if (key) *stop = YES; 78 | }]; 79 | } 80 | 81 | // 查看有没有需要替换的key 82 | if ((!key || [key isEqual:propertyName]) && [self respondsToSelector:@selector(mj_replacedKeyFromPropertyName)]) { 83 | key = [self mj_replacedKeyFromPropertyName][propertyName]; 84 | } 85 | // 兼容旧版本 86 | if ((!key || [key isEqual:propertyName]) && [self respondsToSelector:@selector(replacedKeyFromPropertyName)]) { 87 | key = [self performSelector:@selector(replacedKeyFromPropertyName)][propertyName]; 88 | } 89 | 90 | if (!key || [key isEqual:propertyName]) { 91 | [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) { 92 | NSDictionary *dict = objc_getAssociatedObject(c, &MJReplacedKeyFromPropertyNameKey); 93 | if (dict) { 94 | key = dict[propertyName]; 95 | } 96 | if (key && ![key isEqual:propertyName]) *stop = YES; 97 | }]; 98 | } 99 | 100 | // 2.用属性名作为key 101 | if (!key) key = propertyName; 102 | 103 | return key; 104 | } 105 | 106 | + (Class)propertyObjectClassInArray:(NSString *)propertyName 107 | { 108 | __block id clazz = nil; 109 | if ([self respondsToSelector:@selector(mj_objectClassInArray)]) { 110 | clazz = [self mj_objectClassInArray][propertyName]; 111 | } 112 | // 兼容旧版本 113 | if ([self respondsToSelector:@selector(objectClassInArray)]) { 114 | clazz = [self performSelector:@selector(objectClassInArray)][propertyName]; 115 | } 116 | 117 | if (!clazz) { 118 | [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) { 119 | NSDictionary *dict = objc_getAssociatedObject(c, &MJObjectClassInArrayKey); 120 | if (dict) { 121 | clazz = dict[propertyName]; 122 | } 123 | if (clazz) *stop = YES; 124 | }]; 125 | } 126 | 127 | // 如果是NSString类型 128 | if ([clazz isKindOfClass:[NSString class]]) { 129 | clazz = NSClassFromString(clazz); 130 | } 131 | return clazz; 132 | } 133 | 134 | #pragma mark - --公共方法-- 135 | + (void)mj_enumerateProperties:(MJPropertiesEnumeration)enumeration 136 | { 137 | // 获得成员变量 138 | NSArray *cachedProperties = [self properties]; 139 | 140 | // 遍历成员变量 141 | BOOL stop = NO; 142 | for (MJProperty *property in cachedProperties) { 143 | enumeration(property, &stop); 144 | if (stop) break; 145 | } 146 | } 147 | 148 | #pragma mark - 公共方法 149 | + (NSMutableArray *)properties 150 | { 151 | NSMutableArray *cachedProperties = [self propertyDictForKey:&MJCachedPropertiesKey][NSStringFromClass(self)]; 152 | 153 | if (cachedProperties == nil) { 154 | MJExtensionSemaphoreCreate 155 | MJExtensionSemaphoreWait 156 | 157 | if (cachedProperties == nil) { 158 | cachedProperties = [NSMutableArray array]; 159 | 160 | [self mj_enumerateClasses:^(__unsafe_unretained Class c, BOOL *stop) { 161 | // 1.获得所有的成员变量 162 | unsigned int outCount = 0; 163 | objc_property_t *properties = class_copyPropertyList(c, &outCount); 164 | 165 | // 2.遍历每一个成员变量 166 | for (unsigned int i = 0; i 10 | #import "MJExtensionConst.h" 11 | 12 | @interface NSString (MJExtension) 13 | /** 14 | * 驼峰转下划线(loveYou -> love_you) 15 | */ 16 | - (NSString *)mj_underlineFromCamel; 17 | /** 18 | * 下划线转驼峰(love_you -> loveYou) 19 | */ 20 | - (NSString *)mj_camelFromUnderline; 21 | /** 22 | * 首字母变大写 23 | */ 24 | - (NSString *)mj_firstCharUpper; 25 | /** 26 | * 首字母变小写 27 | */ 28 | - (NSString *)mj_firstCharLower; 29 | 30 | - (BOOL)mj_isPureInt; 31 | 32 | - (NSURL *)mj_url; 33 | @end 34 | 35 | @interface NSString (MJExtensionDeprecated_v_2_5_16) 36 | - (NSString *)underlineFromCamel MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 37 | - (NSString *)camelFromUnderline MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 38 | - (NSString *)firstCharUpper MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 39 | - (NSString *)firstCharLower MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 40 | - (BOOL)isPureInt MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 41 | - (NSURL *)url MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***"); 42 | @end 43 | -------------------------------------------------------------------------------- /Pods/MJExtension/MJExtension/NSString+MJExtension.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+MJExtension.m 3 | // MJExtensionExample 4 | // 5 | // Created by MJ Lee on 15/6/7. 6 | // Copyright (c) 2015年 小码哥. All rights reserved. 7 | // 8 | 9 | #import "NSString+MJExtension.h" 10 | 11 | @implementation NSString (MJExtension) 12 | - (NSString *)mj_underlineFromCamel 13 | { 14 | if (self.length == 0) return self; 15 | NSMutableString *string = [NSMutableString string]; 16 | for (NSUInteger i = 0; i= 2) [string appendString:[cmp substringFromIndex:1]]; 40 | } else { 41 | [string appendString:cmp]; 42 | } 43 | } 44 | return string; 45 | } 46 | 47 | - (NSString *)mj_firstCharLower 48 | { 49 | if (self.length == 0) return self; 50 | NSMutableString *string = [NSMutableString string]; 51 | [string appendString:[NSString stringWithFormat:@"%c", [self characterAtIndex:0]].lowercaseString]; 52 | if (self.length >= 2) [string appendString:[self substringFromIndex:1]]; 53 | return string; 54 | } 55 | 56 | - (NSString *)mj_firstCharUpper 57 | { 58 | if (self.length == 0) return self; 59 | NSMutableString *string = [NSMutableString string]; 60 | [string appendString:[NSString stringWithFormat:@"%c", [self characterAtIndex:0]].uppercaseString]; 61 | if (self.length >= 2) [string appendString:[self substringFromIndex:1]]; 62 | return string; 63 | } 64 | 65 | - (BOOL)mj_isPureInt 66 | { 67 | NSScanner *scan = [NSScanner scannerWithString:self]; 68 | int val; 69 | return [scan scanInt:&val] && [scan isAtEnd]; 70 | } 71 | 72 | - (NSURL *)mj_url 73 | { 74 | // [self stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"!$&'()*+,-./:;=?@_~%#[]"]]; 75 | #pragma clang diagnostic push 76 | #pragma clang diagnostic ignored"-Wdeprecated-declarations" 77 | return [NSURL URLWithString:(NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, (CFStringRef)@"!$&'()*+,-./:;=?@_~%#[]", NULL,kCFStringEncodingUTF8))]; 78 | #pragma clang diagnostic pop 79 | } 80 | @end 81 | 82 | @implementation NSString (MJExtensionDeprecated_v_2_5_16) 83 | - (NSString *)underlineFromCamel 84 | { 85 | return self.mj_underlineFromCamel; 86 | } 87 | 88 | - (NSString *)camelFromUnderline 89 | { 90 | return self.mj_camelFromUnderline; 91 | } 92 | 93 | - (NSString *)firstCharLower 94 | { 95 | return self.mj_firstCharLower; 96 | } 97 | 98 | - (NSString *)firstCharUpper 99 | { 100 | return self.mj_firstCharUpper; 101 | } 102 | 103 | - (BOOL)isPureInt 104 | { 105 | return self.mj_isPureInt; 106 | } 107 | 108 | - (NSURL *)url 109 | { 110 | return self.mj_url; 111 | } 112 | @end 113 | -------------------------------------------------------------------------------- /Pods/MJExtension/README.md: -------------------------------------------------------------------------------- 1 | 2 | ![Logo](http://images.cnitblog.com/blog2015/497279/201505/051004316736641.png) 3 | MJExtension 4 | === 5 | - A fast, convenient and nonintrusive conversion framework between JSON and model. 6 | - 转换速度快、使用简单方便的字典转模型框架 7 | 8 | GitHub:[CoderMJLee](https://github.com/CoderMJLee) | Blog:[mjios(Chinese)](http://www.cnblogs.com/mjios) | PR is welcome,or [feedback](mailto:richermj123go@vip.qq.com) 9 | 10 | 11 | ## Contents 12 | * [Getting Started 【开始使用】](#Getting_Started) 13 | * [Features 【能做什么】](#Features) 14 | * [Installation 【安装】](#Installation) 15 | * [Examples 【示例】](#Examples) 16 | * [JSON -> Model](#JSON_Model) 17 | * [JSONString -> Model](#JSONString_Model) 18 | * [Model contains model](#Model_contains_model) 19 | * [Model contains model-array](#Model_contains_model_array) 20 | * [Model name - JSON key mapping](#Model_name_JSON_key_mapping) 21 | * [JSON array -> model array](#JSON_array_model_array) 22 | * [Model -> JSON](#Model_JSON) 23 | * [Model array -> JSON array](#Model_array_JSON_array) 24 | * [Core Data](#Core_Data) 25 | * [Coding](#Coding) 26 | * [Camel -> underline](#Camel_underline) 27 | * [NSString -> NSDate, nil -> @""](#NSString_NSDate) 28 | * [More use cases](#More_use_cases) 29 | 30 | --- 31 | 32 | # Getting Started【开始使用】 33 | 34 | ## Features【能做什么】 35 | - MJExtension是一套字典和模型之间互相转换的超轻量级框架 36 | * `JSON` --> `Model`、`Core Data Model` 37 | * `JSONString` --> `Model`、`Core Data Model` 38 | * `Model`、`Core Data Model` --> `JSON` 39 | * `JSON Array` --> `Model Array`、`Core Data Model Array` 40 | * `JSONString` --> `Model Array`、`Core Data Model Array` 41 | * `Model Array`、`Core Data Model Array` --> `JSON Array` 42 | * Coding all properties of a model with only one line of code. 43 | * 只需要一行代码,就能实现模型的所有属性进行Coding(归档和解档) 44 | 45 | ## Installation【安装】 46 | 47 | ### From CocoaPods【使用CocoaPods】 48 | 49 | ```ruby 50 | pod 'MJExtension' 51 | ``` 52 | 53 | ### Manually【手动导入】 54 | - Drag all source files under folder `MJExtension` to your project.【将`MJExtension`文件夹中的所有源代码拽入项目中】 55 | - Import the main header file:`#import "MJExtension.h"`【导入主头文件:`#import "MJExtension.h"`】 56 | 57 | ```objc 58 | MJExtension.h 59 | MJConst.h MJConst.m 60 | MJFoundation.h MJFoundation.m 61 | MJProperty.h MJProperty.m 62 | MJType.h MJType.m 63 | NSObject+MJCoding.h NSObject+MJCoding.m 64 | NSObject+MJProperty.h NSObject+MJProperty.m 65 | NSObject+MJKeyValue.h NSObject+MJKeyValue.m 66 | ``` 67 | 68 | # Examples【示例】 69 | 70 | ### The most simple JSON -> Model【最简单的字典转模型】 71 | 72 | ```objc 73 | typedef enum { 74 | SexMale, 75 | SexFemale 76 | } Sex; 77 | 78 | @interface User : NSObject 79 | @property (copy, nonatomic) NSString *name; 80 | @property (copy, nonatomic) NSString *icon; 81 | @property (assign, nonatomic) unsigned int age; 82 | @property (copy, nonatomic) NSString *height; 83 | @property (strong, nonatomic) NSNumber *money; 84 | @property (assign, nonatomic) Sex sex; 85 | @property (assign, nonatomic, getter=isGay) BOOL gay; 86 | @end 87 | 88 | /***********************************************/ 89 | 90 | NSDictionary *dict = @{ 91 | @"name" : @"Jack", 92 | @"icon" : @"lufy.png", 93 | @"age" : @20, 94 | @"height" : @"1.55", 95 | @"money" : @100.9, 96 | @"sex" : @(SexFemale), 97 | @"gay" : @"true" 98 | // @"gay" : @"1" 99 | // @"gay" : @"NO" 100 | }; 101 | 102 | // JSON -> User 103 | User *user = [User mj_objectWithKeyValues:dict]; 104 | 105 | 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); 106 | // name=Jack, icon=lufy.png, age=20, height=1.550000, money=100.9, sex=1 107 | ``` 108 | 109 | ### JSONString -> Model【JSON字符串转模型】 110 | 111 | ```objc 112 | // 1.Define a JSONString 113 | NSString *jsonString = @"{\"name\":\"Jack\", \"icon\":\"lufy.png\", \"age\":20}"; 114 | 115 | // 2.JSONString -> User 116 | User *user = [User mj_objectWithKeyValues:jsonString]; 117 | 118 | // 3.Print user's properties 119 | NSLog(@"name=%@, icon=%@, age=%d", user.name, user.icon, user.age); 120 | // name=Jack, icon=lufy.png, age=20 121 | ``` 122 | 123 | ### Model contains model【模型中嵌套模型】 124 | 125 | ```objc 126 | @interface Status : NSObject 127 | @property (copy, nonatomic) NSString *text; 128 | @property (strong, nonatomic) User *user; 129 | @property (strong, nonatomic) Status *retweetedStatus; 130 | @end 131 | 132 | /***********************************************/ 133 | 134 | NSDictionary *dict = @{ 135 | @"text" : @"Agree!Nice weather!", 136 | @"user" : @{ 137 | @"name" : @"Jack", 138 | @"icon" : @"lufy.png" 139 | }, 140 | @"retweetedStatus" : @{ 141 | @"text" : @"Nice weather!", 142 | @"user" : @{ 143 | @"name" : @"Rose", 144 | @"icon" : @"nami.png" 145 | } 146 | } 147 | }; 148 | 149 | // JSON -> Status 150 | Status *status = [Status mj_objectWithKeyValues:dict]; 151 | 152 | NSString *text = status.text; 153 | NSString *name = status.user.name; 154 | NSString *icon = status.user.icon; 155 | NSLog(@"text=%@, name=%@, icon=%@", text, name, icon); 156 | // text=Agree!Nice weather!, name=Jack, icon=lufy.png 157 | 158 | NSString *text2 = status.retweetedStatus.text; 159 | NSString *name2 = status.retweetedStatus.user.name; 160 | NSString *icon2 = status.retweetedStatus.user.icon; 161 | NSLog(@"text2=%@, name2=%@, icon2=%@", text2, name2, icon2); 162 | // text2=Nice weather!, name2=Rose, icon2=nami.png 163 | ``` 164 | 165 | ### Model contains model-array【模型中有个数组属性,数组里面又要装着其他模型】 166 | 167 | ```objc 168 | @interface Ad : NSObject 169 | @property (copy, nonatomic) NSString *image; 170 | @property (copy, nonatomic) NSString *url; 171 | @end 172 | 173 | @interface StatusResult : NSObject 174 | /** Contatins status model */ 175 | @property (strong, nonatomic) NSMutableArray *statuses; 176 | /** Contatins ad model */ 177 | @property (strong, nonatomic) NSArray *ads; 178 | @property (strong, nonatomic) NSNumber *totalNumber; 179 | @end 180 | 181 | /***********************************************/ 182 | 183 | // Tell MJExtension what type of model will be contained in statuses and ads. 184 | [StatusResult mj_setupObjectClassInArray:^NSDictionary *{ 185 | return @{ 186 | @"statuses" : @"Status", 187 | // @"statuses" : [Status class], 188 | @"ads" : @"Ad" 189 | // @"ads" : [Ad class] 190 | }; 191 | }]; 192 | // Equals: StatusResult.m implements +mj_objectClassInArray method. 193 | 194 | NSDictionary *dict = @{ 195 | @"statuses" : @[ 196 | @{ 197 | @"text" : @"Nice weather!", 198 | @"user" : @{ 199 | @"name" : @"Rose", 200 | @"icon" : @"nami.png" 201 | } 202 | }, 203 | @{ 204 | @"text" : @"Go camping tomorrow!", 205 | @"user" : @{ 206 | @"name" : @"Jack", 207 | @"icon" : @"lufy.png" 208 | } 209 | } 210 | ], 211 | @"ads" : @[ 212 | @{ 213 | @"image" : @"ad01.png", 214 | @"url" : @"http://www.ad01.com" 215 | }, 216 | @{ 217 | @"image" : @"ad02.png", 218 | @"url" : @"http://www.ad02.com" 219 | } 220 | ], 221 | @"totalNumber" : @"2014" 222 | }; 223 | 224 | // JSON -> StatusResult 225 | StatusResult *result = [StatusResult mj_objectWithKeyValues:dict]; 226 | 227 | NSLog(@"totalNumber=%@", result.totalNumber); 228 | // totalNumber=2014 229 | 230 | // Printing 231 | for (Status *status in result.statuses) { 232 | NSString *text = status.text; 233 | NSString *name = status.user.name; 234 | NSString *icon = status.user.icon; 235 | NSLog(@"text=%@, name=%@, icon=%@", text, name, icon); 236 | } 237 | // text=Nice weather!, name=Rose, icon=nami.png 238 | // text=Go camping tomorrow!, name=Jack, icon=lufy.png 239 | 240 | // Printing 241 | for (Ad *ad in result.ads) { 242 | NSLog(@"image=%@, url=%@", ad.image, ad.url); 243 | } 244 | // image=ad01.png, url=http://www.ad01.com 245 | // image=ad02.png, url=http://www.ad02.com 246 | ``` 247 | 248 | ### Model name - JSON key mapping【模型中的属性名和字典中的key不相同(或者需要多级映射)】 249 | 250 | ```objc 251 | @interface Bag : NSObject 252 | @property (copy, nonatomic) NSString *name; 253 | @property (assign, nonatomic) double price; 254 | @end 255 | 256 | @interface Student : NSObject 257 | @property (copy, nonatomic) NSString *ID; 258 | @property (copy, nonatomic) NSString *desc; 259 | @property (copy, nonatomic) NSString *nowName; 260 | @property (copy, nonatomic) NSString *oldName; 261 | @property (copy, nonatomic) NSString *nameChangedTime; 262 | @property (strong, nonatomic) Bag *bag; 263 | @end 264 | 265 | /***********************************************/ 266 | 267 | // How to map 268 | [Student mj_setupReplacedKeyFromPropertyName:^NSDictionary *{ 269 | return @{ 270 | @"ID" : @"id", 271 | @"desc" : @"description", 272 | @"oldName" : @"name.oldName", 273 | @"nowName" : @"name.newName", 274 | @"nameChangedTime" : @"name.info[1].nameChangedTime", 275 | @"bag" : @"other.bag" 276 | }; 277 | }]; 278 | // Equals: Student.m implements +mj_replacedKeyFromPropertyName method. 279 | 280 | NSDictionary *dict = @{ 281 | @"id" : @"20", 282 | @"description" : @"kids", 283 | @"name" : @{ 284 | @"newName" : @"lufy", 285 | @"oldName" : @"kitty", 286 | @"info" : @[ 287 | @"test-data", 288 | @{ 289 | @"nameChangedTime" : @"2013-08" 290 | } 291 | ] 292 | }, 293 | @"other" : @{ 294 | @"bag" : @{ 295 | @"name" : @"a red bag", 296 | @"price" : @100.7 297 | } 298 | } 299 | }; 300 | 301 | // JSON -> Student 302 | Student *stu = [Student mj_objectWithKeyValues:dict]; 303 | 304 | // Printing 305 | NSLog(@"ID=%@, desc=%@, oldName=%@, nowName=%@, nameChangedTime=%@", 306 | stu.ID, stu.desc, stu.oldName, stu.nowName, stu.nameChangedTime); 307 | // ID=20, desc=kids, oldName=kitty, nowName=lufy, nameChangedTime=2013-08 308 | NSLog(@"bagName=%@, bagPrice=%f", stu.bag.name, stu.bag.price); 309 | // bagName=a red bag, bagPrice=100.700000 310 | ``` 311 | 312 | 313 | ### JSON array -> model array【将一个字典数组转成模型数组】 314 | 315 | ```objc 316 | NSArray *dictArray = @[ 317 | @{ 318 | @"name" : @"Jack", 319 | @"icon" : @"lufy.png" 320 | }, 321 | @{ 322 | @"name" : @"Rose", 323 | @"icon" : @"nami.png" 324 | } 325 | ]; 326 | 327 | // JSON array -> User array 328 | NSArray *userArray = [User mj_objectArrayWithKeyValuesArray:dictArray]; 329 | 330 | // Printing 331 | for (User *user in userArray) { 332 | NSLog(@"name=%@, icon=%@", user.name, user.icon); 333 | } 334 | // name=Jack, icon=lufy.png 335 | // name=Rose, icon=nami.png 336 | ``` 337 | 338 | ### Model -> JSON【将一个模型转成字典】 339 | ```objc 340 | // New model 341 | User *user = [[User alloc] init]; 342 | user.name = @"Jack"; 343 | user.icon = @"lufy.png"; 344 | 345 | Status *status = [[Status alloc] init]; 346 | status.user = user; 347 | status.text = @"Nice mood!"; 348 | 349 | // Status -> JSON 350 | NSDictionary *statusDict = status.mj_keyValues; 351 | NSLog(@"%@", statusDict); 352 | /* 353 | { 354 | text = "Nice mood!"; 355 | user = { 356 | icon = "lufy.png"; 357 | name = Jack; 358 | }; 359 | } 360 | */ 361 | 362 | // More complex situation 363 | Student *stu = [[Student alloc] init]; 364 | stu.ID = @"123"; 365 | stu.oldName = @"rose"; 366 | stu.nowName = @"jack"; 367 | stu.desc = @"handsome"; 368 | stu.nameChangedTime = @"2018-09-08"; 369 | 370 | Bag *bag = [[Bag alloc] init]; 371 | bag.name = @"a red bag"; 372 | bag.price = 205; 373 | stu.bag = bag; 374 | 375 | NSDictionary *stuDict = stu.mj_keyValues; 376 | NSLog(@"%@", stuDict); 377 | /* 378 | { 379 | ID = 123; 380 | bag = { 381 | name = "\U5c0f\U4e66\U5305"; 382 | price = 205; 383 | }; 384 | desc = handsome; 385 | nameChangedTime = "2018-09-08"; 386 | nowName = jack; 387 | oldName = rose; 388 | } 389 | */ 390 | ``` 391 | 392 | ### Model array -> JSON array【将一个模型数组转成字典数组】 393 | 394 | ```objc 395 | // New model array 396 | User *user1 = [[User alloc] init]; 397 | user1.name = @"Jack"; 398 | user1.icon = @"lufy.png"; 399 | 400 | User *user2 = [[User alloc] init]; 401 | user2.name = @"Rose"; 402 | user2.icon = @"nami.png"; 403 | 404 | NSArray *userArray = @[user1, user2]; 405 | 406 | // Model array -> JSON array 407 | NSArray *dictArray = [User mj_keyValuesArrayWithObjectArray:userArray]; 408 | NSLog(@"%@", dictArray); 409 | /* 410 | ( 411 | { 412 | icon = "lufy.png"; 413 | name = Jack; 414 | }, 415 | { 416 | icon = "nami.png"; 417 | name = Rose; 418 | } 419 | ) 420 | */ 421 | ``` 422 | 423 | ### Core Data 424 | 425 | ```objc 426 | NSDictionary *dict = @{ 427 | @"name" : @"Jack", 428 | @"icon" : @"lufy.png", 429 | @"age" : @20, 430 | @"height" : @1.55, 431 | @"money" : @"100.9", 432 | @"sex" : @(SexFemale), 433 | @"gay" : @"true" 434 | }; 435 | 436 | // This demo just provide simple steps 437 | NSManagedObjectContext *context = nil; 438 | User *user = [User mj_objectWithKeyValues:dict context:context]; 439 | 440 | [context save:nil]; 441 | ``` 442 | 443 | ### Coding 444 | 445 | ```objc 446 | #import "MJExtension.h" 447 | 448 | @implementation Bag 449 | // NSCoding Implementation 450 | MJExtensionCodingImplementation 451 | @end 452 | 453 | /***********************************************/ 454 | 455 | // what properties not to be coded 456 | [Bag mj_setupIgnoredCodingPropertyNames:^NSArray *{ 457 | return @[@"name"]; 458 | }]; 459 | // Equals: Bag.m implements +mj_ignoredCodingPropertyNames method. 460 | 461 | // Create model 462 | Bag *bag = [[Bag alloc] init]; 463 | bag.name = @"Red bag"; 464 | bag.price = 200.8; 465 | 466 | NSString *file = [NSHomeDirectory() stringByAppendingPathComponent:@"Desktop/bag.data"]; 467 | // Encoding 468 | [NSKeyedArchiver archiveRootObject:bag toFile:file]; 469 | 470 | // Decoding 471 | Bag *decodedBag = [NSKeyedUnarchiver unarchiveObjectWithFile:file]; 472 | NSLog(@"name=%@, price=%f", decodedBag.name, decodedBag.price); 473 | // name=(null), price=200.800000 474 | ``` 475 | 476 | ### Camel -> underline【统一转换属性名(比如驼峰转下划线)】 477 | ```objc 478 | // Dog 479 | #import "MJExtension.h" 480 | 481 | @implementation Dog 482 | + (NSString *)mj_replacedKeyFromPropertyName121:(NSString *)propertyName 483 | { 484 | // nickName -> nick_name 485 | return [propertyName mj_underlineFromCamel]; 486 | } 487 | @end 488 | 489 | // NSDictionary 490 | NSDictionary *dict = @{ 491 | @"nick_name" : @"旺财", 492 | @"sale_price" : @"10.5", 493 | @"run_speed" : @"100.9" 494 | }; 495 | // NSDictionary -> Dog 496 | Dog *dog = [Dog mj_objectWithKeyValues:dict]; 497 | 498 | // printing 499 | NSLog(@"nickName=%@, scalePrice=%f runSpeed=%f", dog.nickName, dog.salePrice, dog.runSpeed); 500 | ``` 501 | 502 | ### NSString -> NSDate, nil -> @""【过滤字典的值(比如字符串日期处理为NSDate、字符串nil处理为@"")】 503 | ```objc 504 | // Book 505 | #import "MJExtension.h" 506 | 507 | @implementation Book 508 | - (id)mj_newValueFromOldValue:(id)oldValue property:(MJProperty *)property 509 | { 510 | if ([property.name isEqualToString:@"publisher"]) { 511 | if (oldValue == nil) return @""; 512 | } else if (property.type.typeClass == [NSDate class]) { 513 | NSDateFormatter *fmt = [[NSDateFormatter alloc] init]; 514 | fmt.dateFormat = @"yyyy-MM-dd"; 515 | return [fmt dateFromString:oldValue]; 516 | } 517 | 518 | return oldValue; 519 | } 520 | @end 521 | 522 | // NSDictionary 523 | NSDictionary *dict = @{ 524 | @"name" : @"5分钟突破iOS开发", 525 | @"publishedTime" : @"2011-09-10" 526 | }; 527 | // NSDictionary -> Book 528 | Book *book = [Book mj_objectWithKeyValues:dict]; 529 | 530 | // printing 531 | NSLog(@"name=%@, publisher=%@, publishedTime=%@", book.name, book.publisher, book.publishedTime); 532 | ``` 533 | 534 | ### More use cases【更多用法】 535 | - Please reference to `NSObject+MJKeyValue.h` and `NSObject+MJCoding.h` 536 | 537 | 538 | ## 期待 539 | * 如果在使用过程中遇到BUG,希望你能Issues我,谢谢(或者尝试下载最新的框架代码看看BUG修复没有) 540 | * 如果在使用过程中发现功能不够用,希望你能Issues我,我非常想为这个框架增加更多好用的功能,谢谢 541 | * 如果你想为MJExtension输出代码,请拼命Pull Requests我 542 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - MJExtension (3.0.15.1) 3 | - YYModel (1.0.4) 4 | 5 | DEPENDENCIES: 6 | - MJExtension 7 | - YYModel 8 | 9 | SPEC REPOS: 10 | https://github.com/cocoapods/specs.git: 11 | - MJExtension 12 | - YYModel 13 | 14 | SPEC CHECKSUMS: 15 | MJExtension: 19bc33ce2eee2d319760f5622562cf581a6ff756 16 | YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30 17 | 18 | PODFILE CHECKSUM: 9364ab88efc702c5c257fea881b1332094290091 19 | 20 | COCOAPODS: 1.5.3 21 | -------------------------------------------------------------------------------- /Pods/Target Support Files/MJExtension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 3.0.15 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/MJExtension/MJExtension-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_MJExtension : NSObject 3 | @end 4 | @implementation PodsDummy_MJExtension 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/MJExtension/MJExtension-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/MJExtension/MJExtension-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "MJExtension.h" 14 | #import "MJExtensionConst.h" 15 | #import "MJFoundation.h" 16 | #import "MJProperty.h" 17 | #import "MJPropertyKey.h" 18 | #import "MJPropertyType.h" 19 | #import "NSObject+MJClass.h" 20 | #import "NSObject+MJCoding.h" 21 | #import "NSObject+MJKeyValue.h" 22 | #import "NSObject+MJProperty.h" 23 | #import "NSString+MJExtension.h" 24 | 25 | FOUNDATION_EXPORT double MJExtensionVersionNumber; 26 | FOUNDATION_EXPORT const unsigned char MJExtensionVersionString[]; 27 | 28 | -------------------------------------------------------------------------------- /Pods/Target Support Files/MJExtension/MJExtension.modulemap: -------------------------------------------------------------------------------- 1 | framework module MJExtension { 2 | umbrella header "MJExtension-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/MJExtension/MJExtension.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/MJExtension 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | PODS_BUILD_DIR = ${BUILD_DIR} 4 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 5 | PODS_ROOT = ${SRCROOT} 6 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/MJExtension 7 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 8 | SKIP_INSTALL = YES 9 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YBModelFileDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YBModelFileDemo/Pods-YBModelFileDemo-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## MJExtension 5 | 6 | Copyright (c) 2013-2015 MJExtension (https://github.com/CoderMJLee/MJExtension) 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | 27 | ## YYModel 28 | 29 | The MIT License (MIT) 30 | 31 | Copyright (c) 2015 ibireme 32 | 33 | Permission is hereby granted, free of charge, to any person obtaining a copy 34 | of this software and associated documentation files (the "Software"), to deal 35 | in the Software without restriction, including without limitation the rights 36 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 37 | copies of the Software, and to permit persons to whom the Software is 38 | furnished to do so, subject to the following conditions: 39 | 40 | The above copyright notice and this permission notice shall be included in all 41 | copies or substantial portions of the Software. 42 | 43 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 44 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 45 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 46 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 47 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 48 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 49 | SOFTWARE. 50 | 51 | 52 | Generated by CocoaPods - https://cocoapods.org 53 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YBModelFileDemo/Pods-YBModelFileDemo-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Copyright (c) 2013-2015 MJExtension (https://github.com/CoderMJLee/MJExtension) 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | License 38 | MIT 39 | Title 40 | MJExtension 41 | Type 42 | PSGroupSpecifier 43 | 44 | 45 | FooterText 46 | The MIT License (MIT) 47 | 48 | Copyright (c) 2015 ibireme <ibireme@gmail.com> 49 | 50 | Permission is hereby granted, free of charge, to any person obtaining a copy 51 | of this software and associated documentation files (the "Software"), to deal 52 | in the Software without restriction, including without limitation the rights 53 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 54 | copies of the Software, and to permit persons to whom the Software is 55 | furnished to do so, subject to the following conditions: 56 | 57 | The above copyright notice and this permission notice shall be included in all 58 | copies or substantial portions of the Software. 59 | 60 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 61 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 62 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 63 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 64 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 65 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 66 | SOFTWARE. 67 | 68 | 69 | License 70 | MIT 71 | Title 72 | YYModel 73 | Type 74 | PSGroupSpecifier 75 | 76 | 77 | FooterText 78 | Generated by CocoaPods - https://cocoapods.org 79 | Title 80 | 81 | Type 82 | PSGroupSpecifier 83 | 84 | 85 | StringsTable 86 | Acknowledgements 87 | Title 88 | Acknowledgements 89 | 90 | 91 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YBModelFileDemo/Pods-YBModelFileDemo-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_YBModelFileDemo : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_YBModelFileDemo 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YBModelFileDemo/Pods-YBModelFileDemo-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then 7 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy 8 | # frameworks to, so exit 0 (signalling the script phase was successful). 9 | exit 0 10 | fi 11 | 12 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 13 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 14 | 15 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" 16 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 17 | 18 | # Used as a return value for each invocation of `strip_invalid_archs` function. 19 | STRIP_BINARY_RETVAL=0 20 | 21 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 22 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 23 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 24 | 25 | # Copies and strips a vendored framework 26 | install_framework() 27 | { 28 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 29 | local source="${BUILT_PRODUCTS_DIR}/$1" 30 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 31 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 32 | elif [ -r "$1" ]; then 33 | local source="$1" 34 | fi 35 | 36 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 37 | 38 | if [ -L "${source}" ]; then 39 | echo "Symlinked..." 40 | source="$(readlink "${source}")" 41 | fi 42 | 43 | # Use filter instead of exclude so missing patterns don't throw errors. 44 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 45 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 46 | 47 | local basename 48 | basename="$(basename -s .framework "$1")" 49 | binary="${destination}/${basename}.framework/${basename}" 50 | if ! [ -r "$binary" ]; then 51 | binary="${destination}/${basename}" 52 | fi 53 | 54 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 55 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 56 | strip_invalid_archs "$binary" 57 | fi 58 | 59 | # Resign the code if required by the build settings to avoid unstable apps 60 | code_sign_if_enabled "${destination}/$(basename "$1")" 61 | 62 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 63 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 64 | local swift_runtime_libs 65 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 66 | for lib in $swift_runtime_libs; do 67 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 68 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 69 | code_sign_if_enabled "${destination}/${lib}" 70 | done 71 | fi 72 | } 73 | 74 | # Copies and strips a vendored dSYM 75 | install_dsym() { 76 | local source="$1" 77 | if [ -r "$source" ]; then 78 | # Copy the dSYM into a the targets temp dir. 79 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" 80 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" 81 | 82 | local basename 83 | basename="$(basename -s .framework.dSYM "$source")" 84 | binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}" 85 | 86 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 87 | if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then 88 | strip_invalid_archs "$binary" 89 | fi 90 | 91 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then 92 | # Move the stripped file into its final destination. 93 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" 94 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}" 95 | else 96 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. 97 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM" 98 | fi 99 | fi 100 | } 101 | 102 | # Signs a framework with the provided identity 103 | code_sign_if_enabled() { 104 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 105 | # Use the current code_sign_identitiy 106 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 107 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" 108 | 109 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 110 | code_sign_cmd="$code_sign_cmd &" 111 | fi 112 | echo "$code_sign_cmd" 113 | eval "$code_sign_cmd" 114 | fi 115 | } 116 | 117 | # Strip invalid architectures 118 | strip_invalid_archs() { 119 | binary="$1" 120 | # Get architectures for current target binary 121 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" 122 | # Intersect them with the architectures we are building for 123 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" 124 | # If there are no archs supported by this binary then warn the user 125 | if [[ -z "$intersected_archs" ]]; then 126 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." 127 | STRIP_BINARY_RETVAL=0 128 | return 129 | fi 130 | stripped="" 131 | for arch in $binary_archs; do 132 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 133 | # Strip non-valid architectures in-place 134 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 135 | stripped="$stripped $arch" 136 | fi 137 | done 138 | if [[ "$stripped" ]]; then 139 | echo "Stripped $binary of architectures:$stripped" 140 | fi 141 | STRIP_BINARY_RETVAL=1 142 | } 143 | 144 | 145 | if [[ "$CONFIGURATION" == "Debug" ]]; then 146 | install_framework "${BUILT_PRODUCTS_DIR}/MJExtension/MJExtension.framework" 147 | install_framework "${BUILT_PRODUCTS_DIR}/YYModel/YYModel.framework" 148 | fi 149 | if [[ "$CONFIGURATION" == "Release" ]]; then 150 | install_framework "${BUILT_PRODUCTS_DIR}/MJExtension/MJExtension.framework" 151 | install_framework "${BUILT_PRODUCTS_DIR}/YYModel/YYModel.framework" 152 | fi 153 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 154 | wait 155 | fi 156 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YBModelFileDemo/Pods-YBModelFileDemo-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then 7 | # If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy 8 | # resources to, so exit 0 (signalling the script phase was successful). 9 | exit 0 10 | fi 11 | 12 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 13 | 14 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 15 | > "$RESOURCES_TO_COPY" 16 | 17 | XCASSET_FILES=() 18 | 19 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 20 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 21 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 22 | 23 | case "${TARGETED_DEVICE_FAMILY:-}" in 24 | 1,2) 25 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 26 | ;; 27 | 1) 28 | TARGET_DEVICE_ARGS="--target-device iphone" 29 | ;; 30 | 2) 31 | TARGET_DEVICE_ARGS="--target-device ipad" 32 | ;; 33 | 3) 34 | TARGET_DEVICE_ARGS="--target-device tv" 35 | ;; 36 | 4) 37 | TARGET_DEVICE_ARGS="--target-device watch" 38 | ;; 39 | *) 40 | TARGET_DEVICE_ARGS="--target-device mac" 41 | ;; 42 | esac 43 | 44 | install_resource() 45 | { 46 | if [[ "$1" = /* ]] ; then 47 | RESOURCE_PATH="$1" 48 | else 49 | RESOURCE_PATH="${PODS_ROOT}/$1" 50 | fi 51 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 52 | cat << EOM 53 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 54 | EOM 55 | exit 1 56 | fi 57 | case $RESOURCE_PATH in 58 | *.storyboard) 59 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 60 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 61 | ;; 62 | *.xib) 63 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 64 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 65 | ;; 66 | *.framework) 67 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 68 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 69 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 70 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 71 | ;; 72 | *.xcdatamodel) 73 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 74 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 75 | ;; 76 | *.xcdatamodeld) 77 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 78 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 79 | ;; 80 | *.xcmappingmodel) 81 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 82 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 83 | ;; 84 | *.xcassets) 85 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 86 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 87 | ;; 88 | *) 89 | echo "$RESOURCE_PATH" || true 90 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 91 | ;; 92 | esac 93 | } 94 | 95 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 96 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 97 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 98 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 99 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 100 | fi 101 | rm -f "$RESOURCES_TO_COPY" 102 | 103 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ] 104 | then 105 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 106 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 107 | while read line; do 108 | if [[ $line != "${PODS_ROOT}*" ]]; then 109 | XCASSET_FILES+=("$line") 110 | fi 111 | done <<<"$OTHER_XCASSETS" 112 | 113 | if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then 114 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 115 | else 116 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist" 117 | fi 118 | fi 119 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YBModelFileDemo/Pods-YBModelFileDemo-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_YBModelFileDemoVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_YBModelFileDemoVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YBModelFileDemo/Pods-YBModelFileDemo.debug.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "${PODS_CONFIGURATION_BUILD_DIR}/YYModel" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension/MJExtension.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/YYModel/YYModel.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "MJExtension" -framework "YYModel" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YBModelFileDemo/Pods-YBModelFileDemo.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_YBModelFileDemo { 2 | umbrella header "Pods-YBModelFileDemo-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-YBModelFileDemo/Pods-YBModelFileDemo.release.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "${PODS_CONFIGURATION_BUILD_DIR}/YYModel" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension/MJExtension.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/YYModel/YYModel.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "MJExtension" -framework "YYModel" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | -------------------------------------------------------------------------------- /Pods/Target Support Files/YYModel/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.4 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/YYModel/YYModel-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_YYModel : NSObject 3 | @end 4 | @implementation PodsDummy_YYModel 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/YYModel/YYModel-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/YYModel/YYModel-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "NSObject+YYModel.h" 14 | #import "YYClassInfo.h" 15 | #import "YYModel.h" 16 | 17 | FOUNDATION_EXPORT double YYModelVersionNumber; 18 | FOUNDATION_EXPORT const unsigned char YYModelVersionString[]; 19 | 20 | -------------------------------------------------------------------------------- /Pods/Target Support Files/YYModel/YYModel.modulemap: -------------------------------------------------------------------------------- 1 | framework module YYModel { 2 | umbrella header "YYModel-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/YYModel/YYModel.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/YYModel 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_LDFLAGS = -framework "CoreFoundation" -framework "Foundation" 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/YYModel 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | -------------------------------------------------------------------------------- /Pods/YYModel/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 ibireme 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Pods/YYModel/YYModel/NSObject+YYModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+YYModel.h 3 | // YYModel 4 | // 5 | // Created by ibireme on 15/5/10. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | Provide some data-model method: 18 | 19 | * Convert json to any object, or convert any object to json. 20 | * Set object properties with a key-value dictionary (like KVC). 21 | * Implementations of `NSCoding`, `NSCopying`, `-hash` and `-isEqual:`. 22 | 23 | See `YYModel` protocol for custom methods. 24 | 25 | 26 | Sample Code: 27 | 28 | ********************** json convertor ********************* 29 | @interface YYAuthor : NSObject 30 | @property (nonatomic, strong) NSString *name; 31 | @property (nonatomic, assign) NSDate *birthday; 32 | @end 33 | @implementation YYAuthor 34 | @end 35 | 36 | @interface YYBook : NSObject 37 | @property (nonatomic, copy) NSString *name; 38 | @property (nonatomic, assign) NSUInteger pages; 39 | @property (nonatomic, strong) YYAuthor *author; 40 | @end 41 | @implementation YYBook 42 | @end 43 | 44 | int main() { 45 | // create model from json 46 | YYBook *book = [YYBook yy_modelWithJSON:@"{\"name\": \"Harry Potter\", \"pages\": 256, \"author\": {\"name\": \"J.K.Rowling\", \"birthday\": \"1965-07-31\" }}"]; 47 | 48 | // convert model to json 49 | NSString *json = [book yy_modelToJSONString]; 50 | // {"author":{"name":"J.K.Rowling","birthday":"1965-07-31T00:00:00+0000"},"name":"Harry Potter","pages":256} 51 | } 52 | 53 | ********************** Coding/Copying/hash/equal ********************* 54 | @interface YYShadow :NSObject 55 | @property (nonatomic, copy) NSString *name; 56 | @property (nonatomic, assign) CGSize size; 57 | @end 58 | 59 | @implementation YYShadow 60 | - (void)encodeWithCoder:(NSCoder *)aCoder { [self yy_modelEncodeWithCoder:aCoder]; } 61 | - (id)initWithCoder:(NSCoder *)aDecoder { self = [super init]; return [self yy_modelInitWithCoder:aDecoder]; } 62 | - (id)copyWithZone:(NSZone *)zone { return [self yy_modelCopy]; } 63 | - (NSUInteger)hash { return [self yy_modelHash]; } 64 | - (BOOL)isEqual:(id)object { return [self yy_modelIsEqual:object]; } 65 | @end 66 | 67 | */ 68 | @interface NSObject (YYModel) 69 | 70 | /** 71 | Creates and returns a new instance of the receiver from a json. 72 | This method is thread-safe. 73 | 74 | @param json A json object in `NSDictionary`, `NSString` or `NSData`. 75 | 76 | @return A new instance created from the json, or nil if an error occurs. 77 | */ 78 | + (nullable instancetype)yy_modelWithJSON:(id)json; 79 | 80 | /** 81 | Creates and returns a new instance of the receiver from a key-value dictionary. 82 | This method is thread-safe. 83 | 84 | @param dictionary A key-value dictionary mapped to the instance's properties. 85 | Any invalid key-value pair in dictionary will be ignored. 86 | 87 | @return A new instance created from the dictionary, or nil if an error occurs. 88 | 89 | @discussion The key in `dictionary` will mapped to the reciever's property name, 90 | and the value will set to the property. If the value's type does not match the 91 | property, this method will try to convert the value based on these rules: 92 | 93 | `NSString` or `NSNumber` -> c number, such as BOOL, int, long, float, NSUInteger... 94 | `NSString` -> NSDate, parsed with format "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd HH:mm:ss" or "yyyy-MM-dd". 95 | `NSString` -> NSURL. 96 | `NSValue` -> struct or union, such as CGRect, CGSize, ... 97 | `NSString` -> SEL, Class. 98 | */ 99 | + (nullable instancetype)yy_modelWithDictionary:(NSDictionary *)dictionary; 100 | 101 | /** 102 | Set the receiver's properties with a json object. 103 | 104 | @discussion Any invalid data in json will be ignored. 105 | 106 | @param json A json object of `NSDictionary`, `NSString` or `NSData`, mapped to the 107 | receiver's properties. 108 | 109 | @return Whether succeed. 110 | */ 111 | - (BOOL)yy_modelSetWithJSON:(id)json; 112 | 113 | /** 114 | Set the receiver's properties with a key-value dictionary. 115 | 116 | @param dic A key-value dictionary mapped to the receiver's properties. 117 | Any invalid key-value pair in dictionary will be ignored. 118 | 119 | @discussion The key in `dictionary` will mapped to the reciever's property name, 120 | and the value will set to the property. If the value's type doesn't match the 121 | property, this method will try to convert the value based on these rules: 122 | 123 | `NSString`, `NSNumber` -> c number, such as BOOL, int, long, float, NSUInteger... 124 | `NSString` -> NSDate, parsed with format "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd HH:mm:ss" or "yyyy-MM-dd". 125 | `NSString` -> NSURL. 126 | `NSValue` -> struct or union, such as CGRect, CGSize, ... 127 | `NSString` -> SEL, Class. 128 | 129 | @return Whether succeed. 130 | */ 131 | - (BOOL)yy_modelSetWithDictionary:(NSDictionary *)dic; 132 | 133 | /** 134 | Generate a json object from the receiver's properties. 135 | 136 | @return A json object in `NSDictionary` or `NSArray`, or nil if an error occurs. 137 | See [NSJSONSerialization isValidJSONObject] for more information. 138 | 139 | @discussion Any of the invalid property is ignored. 140 | If the reciver is `NSArray`, `NSDictionary` or `NSSet`, it just convert 141 | the inner object to json object. 142 | */ 143 | - (nullable id)yy_modelToJSONObject; 144 | 145 | /** 146 | Generate a json string's data from the receiver's properties. 147 | 148 | @return A json string's data, or nil if an error occurs. 149 | 150 | @discussion Any of the invalid property is ignored. 151 | If the reciver is `NSArray`, `NSDictionary` or `NSSet`, it will also convert the 152 | inner object to json string. 153 | */ 154 | - (nullable NSData *)yy_modelToJSONData; 155 | 156 | /** 157 | Generate a json string from the receiver's properties. 158 | 159 | @return A json string, or nil if an error occurs. 160 | 161 | @discussion Any of the invalid property is ignored. 162 | If the reciver is `NSArray`, `NSDictionary` or `NSSet`, it will also convert the 163 | inner object to json string. 164 | */ 165 | - (nullable NSString *)yy_modelToJSONString; 166 | 167 | /** 168 | Copy a instance with the receiver's properties. 169 | 170 | @return A copied instance, or nil if an error occurs. 171 | */ 172 | - (nullable id)yy_modelCopy; 173 | 174 | /** 175 | Encode the receiver's properties to a coder. 176 | 177 | @param aCoder An archiver object. 178 | */ 179 | - (void)yy_modelEncodeWithCoder:(NSCoder *)aCoder; 180 | 181 | /** 182 | Decode the receiver's properties from a decoder. 183 | 184 | @param aDecoder An archiver object. 185 | 186 | @return self 187 | */ 188 | - (id)yy_modelInitWithCoder:(NSCoder *)aDecoder; 189 | 190 | /** 191 | Get a hash code with the receiver's properties. 192 | 193 | @return Hash code. 194 | */ 195 | - (NSUInteger)yy_modelHash; 196 | 197 | /** 198 | Compares the receiver with another object for equality, based on properties. 199 | 200 | @param model Another object. 201 | 202 | @return `YES` if the reciever is equal to the object, otherwise `NO`. 203 | */ 204 | - (BOOL)yy_modelIsEqual:(id)model; 205 | 206 | /** 207 | Description method for debugging purposes based on properties. 208 | 209 | @return A string that describes the contents of the receiver. 210 | */ 211 | - (NSString *)yy_modelDescription; 212 | 213 | @end 214 | 215 | 216 | 217 | /** 218 | Provide some data-model method for NSArray. 219 | */ 220 | @interface NSArray (YYModel) 221 | 222 | /** 223 | Creates and returns an array from a json-array. 224 | This method is thread-safe. 225 | 226 | @param cls The instance's class in array. 227 | @param json A json array of `NSArray`, `NSString` or `NSData`. 228 | Example: [{"name","Mary"},{name:"Joe"}] 229 | 230 | @return A array, or nil if an error occurs. 231 | */ 232 | + (nullable NSArray *)yy_modelArrayWithClass:(Class)cls json:(id)json; 233 | 234 | @end 235 | 236 | 237 | 238 | /** 239 | Provide some data-model method for NSDictionary. 240 | */ 241 | @interface NSDictionary (YYModel) 242 | 243 | /** 244 | Creates and returns a dictionary from a json. 245 | This method is thread-safe. 246 | 247 | @param cls The value instance's class in dictionary. 248 | @param json A json dictionary of `NSDictionary`, `NSString` or `NSData`. 249 | Example: {"user1":{"name","Mary"}, "user2": {name:"Joe"}} 250 | 251 | @return A dictionary, or nil if an error occurs. 252 | */ 253 | + (nullable NSDictionary *)yy_modelDictionaryWithClass:(Class)cls json:(id)json; 254 | @end 255 | 256 | 257 | 258 | /** 259 | If the default model transform does not fit to your model class, implement one or 260 | more method in this protocol to change the default key-value transform process. 261 | There's no need to add '' to your class header. 262 | */ 263 | @protocol YYModel 264 | @optional 265 | 266 | /** 267 | Custom property mapper. 268 | 269 | @discussion If the key in JSON/Dictionary does not match to the model's property name, 270 | implements this method and returns the additional mapper. 271 | 272 | Example: 273 | 274 | json: 275 | { 276 | "n":"Harry Pottery", 277 | "p": 256, 278 | "ext" : { 279 | "desc" : "A book written by J.K.Rowling." 280 | }, 281 | "ID" : 100010 282 | } 283 | 284 | model: 285 | @interface YYBook : NSObject 286 | @property NSString *name; 287 | @property NSInteger page; 288 | @property NSString *desc; 289 | @property NSString *bookID; 290 | @end 291 | 292 | @implementation YYBook 293 | + (NSDictionary *)modelCustomPropertyMapper { 294 | return @{@"name" : @"n", 295 | @"page" : @"p", 296 | @"desc" : @"ext.desc", 297 | @"bookID": @[@"id", @"ID", @"book_id"]}; 298 | } 299 | @end 300 | 301 | @return A custom mapper for properties. 302 | */ 303 | + (nullable NSDictionary *)modelCustomPropertyMapper; 304 | 305 | /** 306 | The generic class mapper for container properties. 307 | 308 | @discussion If the property is a container object, such as NSArray/NSSet/NSDictionary, 309 | implements this method and returns a property->class mapper, tells which kind of 310 | object will be add to the array/set/dictionary. 311 | 312 | Example: 313 | @class YYShadow, YYBorder, YYAttachment; 314 | 315 | @interface YYAttributes 316 | @property NSString *name; 317 | @property NSArray *shadows; 318 | @property NSSet *borders; 319 | @property NSDictionary *attachments; 320 | @end 321 | 322 | @implementation YYAttributes 323 | + (NSDictionary *)modelContainerPropertyGenericClass { 324 | return @{@"shadows" : [YYShadow class], 325 | @"borders" : YYBorder.class, 326 | @"attachments" : @"YYAttachment" }; 327 | } 328 | @end 329 | 330 | @return A class mapper. 331 | */ 332 | + (nullable NSDictionary *)modelContainerPropertyGenericClass; 333 | 334 | /** 335 | If you need to create instances of different classes during json->object transform, 336 | use the method to choose custom class based on dictionary data. 337 | 338 | @discussion If the model implements this method, it will be called to determine resulting class 339 | during `+modelWithJSON:`, `+modelWithDictionary:`, conveting object of properties of parent objects 340 | (both singular and containers via `+modelContainerPropertyGenericClass`). 341 | 342 | Example: 343 | @class YYCircle, YYRectangle, YYLine; 344 | 345 | @implementation YYShape 346 | 347 | + (Class)modelCustomClassForDictionary:(NSDictionary*)dictionary { 348 | if (dictionary[@"radius"] != nil) { 349 | return [YYCircle class]; 350 | } else if (dictionary[@"width"] != nil) { 351 | return [YYRectangle class]; 352 | } else if (dictionary[@"y2"] != nil) { 353 | return [YYLine class]; 354 | } else { 355 | return [self class]; 356 | } 357 | } 358 | 359 | @end 360 | 361 | @param dictionary The json/kv dictionary. 362 | 363 | @return Class to create from this dictionary, `nil` to use current class. 364 | 365 | */ 366 | + (nullable Class)modelCustomClassForDictionary:(NSDictionary *)dictionary; 367 | 368 | /** 369 | All the properties in blacklist will be ignored in model transform process. 370 | Returns nil to ignore this feature. 371 | 372 | @return An array of property's name. 373 | */ 374 | + (nullable NSArray *)modelPropertyBlacklist; 375 | 376 | /** 377 | If a property is not in the whitelist, it will be ignored in model transform process. 378 | Returns nil to ignore this feature. 379 | 380 | @return An array of property's name. 381 | */ 382 | + (nullable NSArray *)modelPropertyWhitelist; 383 | 384 | /** 385 | This method's behavior is similar to `- (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic;`, 386 | but be called before the model transform. 387 | 388 | @discussion If the model implements this method, it will be called before 389 | `+modelWithJSON:`, `+modelWithDictionary:`, `-modelSetWithJSON:` and `-modelSetWithDictionary:`. 390 | If this method returns nil, the transform process will ignore this model. 391 | 392 | @param dic The json/kv dictionary. 393 | 394 | @return Returns the modified dictionary, or nil to ignore this model. 395 | */ 396 | - (NSDictionary *)modelCustomWillTransformFromDictionary:(NSDictionary *)dic; 397 | 398 | /** 399 | If the default json-to-model transform does not fit to your model object, implement 400 | this method to do additional process. You can also use this method to validate the 401 | model's properties. 402 | 403 | @discussion If the model implements this method, it will be called at the end of 404 | `+modelWithJSON:`, `+modelWithDictionary:`, `-modelSetWithJSON:` and `-modelSetWithDictionary:`. 405 | If this method returns NO, the transform process will ignore this model. 406 | 407 | @param dic The json/kv dictionary. 408 | 409 | @return Returns YES if the model is valid, or NO to ignore this model. 410 | */ 411 | - (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic; 412 | 413 | /** 414 | If the default model-to-json transform does not fit to your model class, implement 415 | this method to do additional process. You can also use this method to validate the 416 | json dictionary. 417 | 418 | @discussion If the model implements this method, it will be called at the end of 419 | `-modelToJSONObject` and `-modelToJSONString`. 420 | If this method returns NO, the transform process will ignore this json dictionary. 421 | 422 | @param dic The json dictionary. 423 | 424 | @return Returns YES if the model is valid, or NO to ignore this model. 425 | */ 426 | - (BOOL)modelCustomTransformToDictionary:(NSMutableDictionary *)dic; 427 | 428 | @end 429 | 430 | NS_ASSUME_NONNULL_END 431 | -------------------------------------------------------------------------------- /Pods/YYModel/YYModel/YYClassInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYClassInfo.h 3 | // YYModel 4 | // 5 | // Created by ibireme on 15/5/9. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | #import 14 | 15 | NS_ASSUME_NONNULL_BEGIN 16 | 17 | /** 18 | Type encoding's type. 19 | */ 20 | typedef NS_OPTIONS(NSUInteger, YYEncodingType) { 21 | YYEncodingTypeMask = 0xFF, ///< mask of type value 22 | YYEncodingTypeUnknown = 0, ///< unknown 23 | YYEncodingTypeVoid = 1, ///< void 24 | YYEncodingTypeBool = 2, ///< bool 25 | YYEncodingTypeInt8 = 3, ///< char / BOOL 26 | YYEncodingTypeUInt8 = 4, ///< unsigned char 27 | YYEncodingTypeInt16 = 5, ///< short 28 | YYEncodingTypeUInt16 = 6, ///< unsigned short 29 | YYEncodingTypeInt32 = 7, ///< int 30 | YYEncodingTypeUInt32 = 8, ///< unsigned int 31 | YYEncodingTypeInt64 = 9, ///< long long 32 | YYEncodingTypeUInt64 = 10, ///< unsigned long long 33 | YYEncodingTypeFloat = 11, ///< float 34 | YYEncodingTypeDouble = 12, ///< double 35 | YYEncodingTypeLongDouble = 13, ///< long double 36 | YYEncodingTypeObject = 14, ///< id 37 | YYEncodingTypeClass = 15, ///< Class 38 | YYEncodingTypeSEL = 16, ///< SEL 39 | YYEncodingTypeBlock = 17, ///< block 40 | YYEncodingTypePointer = 18, ///< void* 41 | YYEncodingTypeStruct = 19, ///< struct 42 | YYEncodingTypeUnion = 20, ///< union 43 | YYEncodingTypeCString = 21, ///< char* 44 | YYEncodingTypeCArray = 22, ///< char[10] (for example) 45 | 46 | YYEncodingTypeQualifierMask = 0xFF00, ///< mask of qualifier 47 | YYEncodingTypeQualifierConst = 1 << 8, ///< const 48 | YYEncodingTypeQualifierIn = 1 << 9, ///< in 49 | YYEncodingTypeQualifierInout = 1 << 10, ///< inout 50 | YYEncodingTypeQualifierOut = 1 << 11, ///< out 51 | YYEncodingTypeQualifierBycopy = 1 << 12, ///< bycopy 52 | YYEncodingTypeQualifierByref = 1 << 13, ///< byref 53 | YYEncodingTypeQualifierOneway = 1 << 14, ///< oneway 54 | 55 | YYEncodingTypePropertyMask = 0xFF0000, ///< mask of property 56 | YYEncodingTypePropertyReadonly = 1 << 16, ///< readonly 57 | YYEncodingTypePropertyCopy = 1 << 17, ///< copy 58 | YYEncodingTypePropertyRetain = 1 << 18, ///< retain 59 | YYEncodingTypePropertyNonatomic = 1 << 19, ///< nonatomic 60 | YYEncodingTypePropertyWeak = 1 << 20, ///< weak 61 | YYEncodingTypePropertyCustomGetter = 1 << 21, ///< getter= 62 | YYEncodingTypePropertyCustomSetter = 1 << 22, ///< setter= 63 | YYEncodingTypePropertyDynamic = 1 << 23, ///< @dynamic 64 | }; 65 | 66 | /** 67 | Get the type from a Type-Encoding string. 68 | 69 | @discussion See also: 70 | https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html 71 | https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html 72 | 73 | @param typeEncoding A Type-Encoding string. 74 | @return The encoding type. 75 | */ 76 | YYEncodingType YYEncodingGetType(const char *typeEncoding); 77 | 78 | 79 | /** 80 | Instance variable information. 81 | */ 82 | @interface YYClassIvarInfo : NSObject 83 | @property (nonatomic, assign, readonly) Ivar ivar; ///< ivar opaque struct 84 | @property (nonatomic, strong, readonly) NSString *name; ///< Ivar's name 85 | @property (nonatomic, assign, readonly) ptrdiff_t offset; ///< Ivar's offset 86 | @property (nonatomic, strong, readonly) NSString *typeEncoding; ///< Ivar's type encoding 87 | @property (nonatomic, assign, readonly) YYEncodingType type; ///< Ivar's type 88 | 89 | /** 90 | Creates and returns an ivar info object. 91 | 92 | @param ivar ivar opaque struct 93 | @return A new object, or nil if an error occurs. 94 | */ 95 | - (instancetype)initWithIvar:(Ivar)ivar; 96 | @end 97 | 98 | 99 | /** 100 | Method information. 101 | */ 102 | @interface YYClassMethodInfo : NSObject 103 | @property (nonatomic, assign, readonly) Method method; ///< method opaque struct 104 | @property (nonatomic, strong, readonly) NSString *name; ///< method name 105 | @property (nonatomic, assign, readonly) SEL sel; ///< method's selector 106 | @property (nonatomic, assign, readonly) IMP imp; ///< method's implementation 107 | @property (nonatomic, strong, readonly) NSString *typeEncoding; ///< method's parameter and return types 108 | @property (nonatomic, strong, readonly) NSString *returnTypeEncoding; ///< return value's type 109 | @property (nullable, nonatomic, strong, readonly) NSArray *argumentTypeEncodings; ///< array of arguments' type 110 | 111 | /** 112 | Creates and returns a method info object. 113 | 114 | @param method method opaque struct 115 | @return A new object, or nil if an error occurs. 116 | */ 117 | - (instancetype)initWithMethod:(Method)method; 118 | @end 119 | 120 | 121 | /** 122 | Property information. 123 | */ 124 | @interface YYClassPropertyInfo : NSObject 125 | @property (nonatomic, assign, readonly) objc_property_t property; ///< property's opaque struct 126 | @property (nonatomic, strong, readonly) NSString *name; ///< property's name 127 | @property (nonatomic, assign, readonly) YYEncodingType type; ///< property's type 128 | @property (nonatomic, strong, readonly) NSString *typeEncoding; ///< property's encoding value 129 | @property (nonatomic, strong, readonly) NSString *ivarName; ///< property's ivar name 130 | @property (nullable, nonatomic, assign, readonly) Class cls; ///< may be nil 131 | @property (nullable, nonatomic, strong, readonly) NSArray *protocols; ///< may nil 132 | @property (nonatomic, assign, readonly) SEL getter; ///< getter (nonnull) 133 | @property (nonatomic, assign, readonly) SEL setter; ///< setter (nonnull) 134 | 135 | /** 136 | Creates and returns a property info object. 137 | 138 | @param property property opaque struct 139 | @return A new object, or nil if an error occurs. 140 | */ 141 | - (instancetype)initWithProperty:(objc_property_t)property; 142 | @end 143 | 144 | 145 | /** 146 | Class information for a class. 147 | */ 148 | @interface YYClassInfo : NSObject 149 | @property (nonatomic, assign, readonly) Class cls; ///< class object 150 | @property (nullable, nonatomic, assign, readonly) Class superCls; ///< super class object 151 | @property (nullable, nonatomic, assign, readonly) Class metaCls; ///< class's meta class object 152 | @property (nonatomic, readonly) BOOL isMeta; ///< whether this class is meta class 153 | @property (nonatomic, strong, readonly) NSString *name; ///< class name 154 | @property (nullable, nonatomic, strong, readonly) YYClassInfo *superClassInfo; ///< super class's class info 155 | @property (nullable, nonatomic, strong, readonly) NSDictionary *ivarInfos; ///< ivars 156 | @property (nullable, nonatomic, strong, readonly) NSDictionary *methodInfos; ///< methods 157 | @property (nullable, nonatomic, strong, readonly) NSDictionary *propertyInfos; ///< properties 158 | 159 | /** 160 | If the class is changed (for example: you add a method to this class with 161 | 'class_addMethod()'), you should call this method to refresh the class info cache. 162 | 163 | After called this method, `needUpdate` will returns `YES`, and you should call 164 | 'classInfoWithClass' or 'classInfoWithClassName' to get the updated class info. 165 | */ 166 | - (void)setNeedUpdate; 167 | 168 | /** 169 | If this method returns `YES`, you should stop using this instance and call 170 | `classInfoWithClass` or `classInfoWithClassName` to get the updated class info. 171 | 172 | @return Whether this class info need update. 173 | */ 174 | - (BOOL)needUpdate; 175 | 176 | /** 177 | Get the class info of a specified Class. 178 | 179 | @discussion This method will cache the class info and super-class info 180 | at the first access to the Class. This method is thread-safe. 181 | 182 | @param cls A class. 183 | @return A class info, or nil if an error occurs. 184 | */ 185 | + (nullable instancetype)classInfoWithClass:(Class)cls; 186 | 187 | /** 188 | Get the class info of a specified Class. 189 | 190 | @discussion This method will cache the class info and super-class info 191 | at the first access to the Class. This method is thread-safe. 192 | 193 | @param className A class name. 194 | @return A class info, or nil if an error occurs. 195 | */ 196 | + (nullable instancetype)classInfoWithClassName:(NSString *)className; 197 | 198 | @end 199 | 200 | NS_ASSUME_NONNULL_END 201 | -------------------------------------------------------------------------------- /Pods/YYModel/YYModel/YYClassInfo.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYClassInfo.m 3 | // YYModel 4 | // 5 | // Created by ibireme on 15/5/9. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYClassInfo.h" 13 | #import 14 | 15 | YYEncodingType YYEncodingGetType(const char *typeEncoding) { 16 | char *type = (char *)typeEncoding; 17 | if (!type) return YYEncodingTypeUnknown; 18 | size_t len = strlen(type); 19 | if (len == 0) return YYEncodingTypeUnknown; 20 | 21 | YYEncodingType qualifier = 0; 22 | bool prefix = true; 23 | while (prefix) { 24 | switch (*type) { 25 | case 'r': { 26 | qualifier |= YYEncodingTypeQualifierConst; 27 | type++; 28 | } break; 29 | case 'n': { 30 | qualifier |= YYEncodingTypeQualifierIn; 31 | type++; 32 | } break; 33 | case 'N': { 34 | qualifier |= YYEncodingTypeQualifierInout; 35 | type++; 36 | } break; 37 | case 'o': { 38 | qualifier |= YYEncodingTypeQualifierOut; 39 | type++; 40 | } break; 41 | case 'O': { 42 | qualifier |= YYEncodingTypeQualifierBycopy; 43 | type++; 44 | } break; 45 | case 'R': { 46 | qualifier |= YYEncodingTypeQualifierByref; 47 | type++; 48 | } break; 49 | case 'V': { 50 | qualifier |= YYEncodingTypeQualifierOneway; 51 | type++; 52 | } break; 53 | default: { prefix = false; } break; 54 | } 55 | } 56 | 57 | len = strlen(type); 58 | if (len == 0) return YYEncodingTypeUnknown | qualifier; 59 | 60 | switch (*type) { 61 | case 'v': return YYEncodingTypeVoid | qualifier; 62 | case 'B': return YYEncodingTypeBool | qualifier; 63 | case 'c': return YYEncodingTypeInt8 | qualifier; 64 | case 'C': return YYEncodingTypeUInt8 | qualifier; 65 | case 's': return YYEncodingTypeInt16 | qualifier; 66 | case 'S': return YYEncodingTypeUInt16 | qualifier; 67 | case 'i': return YYEncodingTypeInt32 | qualifier; 68 | case 'I': return YYEncodingTypeUInt32 | qualifier; 69 | case 'l': return YYEncodingTypeInt32 | qualifier; 70 | case 'L': return YYEncodingTypeUInt32 | qualifier; 71 | case 'q': return YYEncodingTypeInt64 | qualifier; 72 | case 'Q': return YYEncodingTypeUInt64 | qualifier; 73 | case 'f': return YYEncodingTypeFloat | qualifier; 74 | case 'd': return YYEncodingTypeDouble | qualifier; 75 | case 'D': return YYEncodingTypeLongDouble | qualifier; 76 | case '#': return YYEncodingTypeClass | qualifier; 77 | case ':': return YYEncodingTypeSEL | qualifier; 78 | case '*': return YYEncodingTypeCString | qualifier; 79 | case '^': return YYEncodingTypePointer | qualifier; 80 | case '[': return YYEncodingTypeCArray | qualifier; 81 | case '(': return YYEncodingTypeUnion | qualifier; 82 | case '{': return YYEncodingTypeStruct | qualifier; 83 | case '@': { 84 | if (len == 2 && *(type + 1) == '?') 85 | return YYEncodingTypeBlock | qualifier; 86 | else 87 | return YYEncodingTypeObject | qualifier; 88 | } 89 | default: return YYEncodingTypeUnknown | qualifier; 90 | } 91 | } 92 | 93 | @implementation YYClassIvarInfo 94 | 95 | - (instancetype)initWithIvar:(Ivar)ivar { 96 | if (!ivar) return nil; 97 | self = [super init]; 98 | _ivar = ivar; 99 | const char *name = ivar_getName(ivar); 100 | if (name) { 101 | _name = [NSString stringWithUTF8String:name]; 102 | } 103 | _offset = ivar_getOffset(ivar); 104 | const char *typeEncoding = ivar_getTypeEncoding(ivar); 105 | if (typeEncoding) { 106 | _typeEncoding = [NSString stringWithUTF8String:typeEncoding]; 107 | _type = YYEncodingGetType(typeEncoding); 108 | } 109 | return self; 110 | } 111 | 112 | @end 113 | 114 | @implementation YYClassMethodInfo 115 | 116 | - (instancetype)initWithMethod:(Method)method { 117 | if (!method) return nil; 118 | self = [super init]; 119 | _method = method; 120 | _sel = method_getName(method); 121 | _imp = method_getImplementation(method); 122 | const char *name = sel_getName(_sel); 123 | if (name) { 124 | _name = [NSString stringWithUTF8String:name]; 125 | } 126 | const char *typeEncoding = method_getTypeEncoding(method); 127 | if (typeEncoding) { 128 | _typeEncoding = [NSString stringWithUTF8String:typeEncoding]; 129 | } 130 | char *returnType = method_copyReturnType(method); 131 | if (returnType) { 132 | _returnTypeEncoding = [NSString stringWithUTF8String:returnType]; 133 | free(returnType); 134 | } 135 | unsigned int argumentCount = method_getNumberOfArguments(method); 136 | if (argumentCount > 0) { 137 | NSMutableArray *argumentTypes = [NSMutableArray new]; 138 | for (unsigned int i = 0; i < argumentCount; i++) { 139 | char *argumentType = method_copyArgumentType(method, i); 140 | NSString *type = argumentType ? [NSString stringWithUTF8String:argumentType] : nil; 141 | [argumentTypes addObject:type ? type : @""]; 142 | if (argumentType) free(argumentType); 143 | } 144 | _argumentTypeEncodings = argumentTypes; 145 | } 146 | return self; 147 | } 148 | 149 | @end 150 | 151 | @implementation YYClassPropertyInfo 152 | 153 | - (instancetype)initWithProperty:(objc_property_t)property { 154 | if (!property) return nil; 155 | self = [super init]; 156 | _property = property; 157 | const char *name = property_getName(property); 158 | if (name) { 159 | _name = [NSString stringWithUTF8String:name]; 160 | } 161 | 162 | YYEncodingType type = 0; 163 | unsigned int attrCount; 164 | objc_property_attribute_t *attrs = property_copyAttributeList(property, &attrCount); 165 | for (unsigned int i = 0; i < attrCount; i++) { 166 | switch (attrs[i].name[0]) { 167 | case 'T': { // Type encoding 168 | if (attrs[i].value) { 169 | _typeEncoding = [NSString stringWithUTF8String:attrs[i].value]; 170 | type = YYEncodingGetType(attrs[i].value); 171 | 172 | if ((type & YYEncodingTypeMask) == YYEncodingTypeObject && _typeEncoding.length) { 173 | NSScanner *scanner = [NSScanner scannerWithString:_typeEncoding]; 174 | if (![scanner scanString:@"@\"" intoString:NULL]) continue; 175 | 176 | NSString *clsName = nil; 177 | if ([scanner scanUpToCharactersFromSet: [NSCharacterSet characterSetWithCharactersInString:@"\"<"] intoString:&clsName]) { 178 | if (clsName.length) _cls = objc_getClass(clsName.UTF8String); 179 | } 180 | 181 | NSMutableArray *protocols = nil; 182 | while ([scanner scanString:@"<" intoString:NULL]) { 183 | NSString* protocol = nil; 184 | if ([scanner scanUpToString:@">" intoString: &protocol]) { 185 | if (protocol.length) { 186 | if (!protocols) protocols = [NSMutableArray new]; 187 | [protocols addObject:protocol]; 188 | } 189 | } 190 | [scanner scanString:@">" intoString:NULL]; 191 | } 192 | _protocols = protocols; 193 | } 194 | } 195 | } break; 196 | case 'V': { // Instance variable 197 | if (attrs[i].value) { 198 | _ivarName = [NSString stringWithUTF8String:attrs[i].value]; 199 | } 200 | } break; 201 | case 'R': { 202 | type |= YYEncodingTypePropertyReadonly; 203 | } break; 204 | case 'C': { 205 | type |= YYEncodingTypePropertyCopy; 206 | } break; 207 | case '&': { 208 | type |= YYEncodingTypePropertyRetain; 209 | } break; 210 | case 'N': { 211 | type |= YYEncodingTypePropertyNonatomic; 212 | } break; 213 | case 'D': { 214 | type |= YYEncodingTypePropertyDynamic; 215 | } break; 216 | case 'W': { 217 | type |= YYEncodingTypePropertyWeak; 218 | } break; 219 | case 'G': { 220 | type |= YYEncodingTypePropertyCustomGetter; 221 | if (attrs[i].value) { 222 | _getter = NSSelectorFromString([NSString stringWithUTF8String:attrs[i].value]); 223 | } 224 | } break; 225 | case 'S': { 226 | type |= YYEncodingTypePropertyCustomSetter; 227 | if (attrs[i].value) { 228 | _setter = NSSelectorFromString([NSString stringWithUTF8String:attrs[i].value]); 229 | } 230 | } // break; commented for code coverage in next line 231 | default: break; 232 | } 233 | } 234 | if (attrs) { 235 | free(attrs); 236 | attrs = NULL; 237 | } 238 | 239 | _type = type; 240 | if (_name.length) { 241 | if (!_getter) { 242 | _getter = NSSelectorFromString(_name); 243 | } 244 | if (!_setter) { 245 | _setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:", [_name substringToIndex:1].uppercaseString, [_name substringFromIndex:1]]); 246 | } 247 | } 248 | return self; 249 | } 250 | 251 | @end 252 | 253 | @implementation YYClassInfo { 254 | BOOL _needUpdate; 255 | } 256 | 257 | - (instancetype)initWithClass:(Class)cls { 258 | if (!cls) return nil; 259 | self = [super init]; 260 | _cls = cls; 261 | _superCls = class_getSuperclass(cls); 262 | _isMeta = class_isMetaClass(cls); 263 | if (!_isMeta) { 264 | _metaCls = objc_getMetaClass(class_getName(cls)); 265 | } 266 | _name = NSStringFromClass(cls); 267 | [self _update]; 268 | 269 | _superClassInfo = [self.class classInfoWithClass:_superCls]; 270 | return self; 271 | } 272 | 273 | - (void)_update { 274 | _ivarInfos = nil; 275 | _methodInfos = nil; 276 | _propertyInfos = nil; 277 | 278 | Class cls = self.cls; 279 | unsigned int methodCount = 0; 280 | Method *methods = class_copyMethodList(cls, &methodCount); 281 | if (methods) { 282 | NSMutableDictionary *methodInfos = [NSMutableDictionary new]; 283 | _methodInfos = methodInfos; 284 | for (unsigned int i = 0; i < methodCount; i++) { 285 | YYClassMethodInfo *info = [[YYClassMethodInfo alloc] initWithMethod:methods[i]]; 286 | if (info.name) methodInfos[info.name] = info; 287 | } 288 | free(methods); 289 | } 290 | unsigned int propertyCount = 0; 291 | objc_property_t *properties = class_copyPropertyList(cls, &propertyCount); 292 | if (properties) { 293 | NSMutableDictionary *propertyInfos = [NSMutableDictionary new]; 294 | _propertyInfos = propertyInfos; 295 | for (unsigned int i = 0; i < propertyCount; i++) { 296 | YYClassPropertyInfo *info = [[YYClassPropertyInfo alloc] initWithProperty:properties[i]]; 297 | if (info.name) propertyInfos[info.name] = info; 298 | } 299 | free(properties); 300 | } 301 | 302 | unsigned int ivarCount = 0; 303 | Ivar *ivars = class_copyIvarList(cls, &ivarCount); 304 | if (ivars) { 305 | NSMutableDictionary *ivarInfos = [NSMutableDictionary new]; 306 | _ivarInfos = ivarInfos; 307 | for (unsigned int i = 0; i < ivarCount; i++) { 308 | YYClassIvarInfo *info = [[YYClassIvarInfo alloc] initWithIvar:ivars[i]]; 309 | if (info.name) ivarInfos[info.name] = info; 310 | } 311 | free(ivars); 312 | } 313 | 314 | if (!_ivarInfos) _ivarInfos = @{}; 315 | if (!_methodInfos) _methodInfos = @{}; 316 | if (!_propertyInfos) _propertyInfos = @{}; 317 | 318 | _needUpdate = NO; 319 | } 320 | 321 | - (void)setNeedUpdate { 322 | _needUpdate = YES; 323 | } 324 | 325 | - (BOOL)needUpdate { 326 | return _needUpdate; 327 | } 328 | 329 | + (instancetype)classInfoWithClass:(Class)cls { 330 | if (!cls) return nil; 331 | static CFMutableDictionaryRef classCache; 332 | static CFMutableDictionaryRef metaCache; 333 | static dispatch_once_t onceToken; 334 | static dispatch_semaphore_t lock; 335 | dispatch_once(&onceToken, ^{ 336 | classCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 337 | metaCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 338 | lock = dispatch_semaphore_create(1); 339 | }); 340 | dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); 341 | YYClassInfo *info = CFDictionaryGetValue(class_isMetaClass(cls) ? metaCache : classCache, (__bridge const void *)(cls)); 342 | if (info && info->_needUpdate) { 343 | [info _update]; 344 | } 345 | dispatch_semaphore_signal(lock); 346 | if (!info) { 347 | info = [[YYClassInfo alloc] initWithClass:cls]; 348 | if (info) { 349 | dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); 350 | CFDictionarySetValue(info.isMeta ? metaCache : classCache, (__bridge const void *)(cls), (__bridge const void *)(info)); 351 | dispatch_semaphore_signal(lock); 352 | } 353 | } 354 | return info; 355 | } 356 | 357 | + (instancetype)classInfoWithClassName:(NSString *)className { 358 | Class cls = NSClassFromString(className); 359 | return [self classInfoWithClass:cls]; 360 | } 361 | 362 | @end 363 | -------------------------------------------------------------------------------- /Pods/YYModel/YYModel/YYModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYModel.h 3 | // YYModel 4 | // 5 | // Created by ibireme on 15/5/10. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | FOUNDATION_EXPORT double YYModelVersionNumber; 16 | FOUNDATION_EXPORT const unsigned char YYModelVersionString[]; 17 | #import 18 | #import 19 | #else 20 | #import "NSObject+YYModel.h" 21 | #import "YYClassInfo.h" 22 | #endif 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # YBModelFile 2 | 3 | [![Cocoapods](https://img.shields.io/cocoapods/v/YBModelFile.svg)](https://cocoapods.org/pods/YBModelFile)  4 | [![Cocoapods](https://img.shields.io/cocoapods/p/YBModelFile.svg)](https://github.com/indulgeIn/YBModelFile)  5 | [![License](https://img.shields.io/github/license/indulgeIn/YBModelFile.svg)](https://github.com/indulgeIn/YBModelFile)  6 | 7 | 8 | 根据 JSON 自动生成 Model 文件(数据模型) 9 | 10 | 技术原理博客:[iOS 效率工具:自动生成 Model 文件](https://www.jianshu.com/p/f30cf05054c6) 11 | 12 | 注意:仅在模拟器下运行有效 13 | 14 | ## 特性 15 | 16 | - 一句代码自动生成数据模型文件 17 | - 支持 YYModel / MJExtension 的自动映射 18 | - 自动过滤转换类名和属性名 19 | - 自动实现 NSCopying / NSCoding 协议方法 20 | - 支持文件创建策略:一个类一组文件或并为一组文件 21 | - 支持属性类型的过滤策略 22 | - 算法处理模块粒度小且面向协议,可自由定制局部算法 23 | 24 | 25 | 26 | ## 安装 27 | 28 | ### CocoaPods 29 | 30 | 1. 在 Podfile 中添加 `pod 'YBModelFile', :configurations => ['Debug']`。 31 | 2. 执行 `pod install` 或 `pod update`。 32 | 3. 导入 ``。 33 | 34 | 若搜索不到库,可使用 rm ~/Library/Caches/CocoaPods/search_index.json 移除本地索引然后再执行安装,或者更新一下 CocoaPods 版本。 35 | 36 | ### 手动导入 37 | 38 | 1. 下载 YBModelFile 文件夹所有内容并且拖入你的工程中。 39 | 2. 导入 `YBModelFile.h`。 40 | 41 | 42 | ## 用法 43 | 44 | 可下载 DEMO 查看示例。 45 | 46 | ### 基本使用 47 | 48 | ```objc 49 | NSString *name = ...; //主 Model 文件名字 50 | id data = ...; //json数据 51 | [YBModelFile createFileWithName:name data:data]; 52 | ``` 53 | 一句代码调用过后,工具会自动在桌面上创建一个 YBModelFile-Workspace 文件夹,之后所有自动创建的 Model 文件会存储在该文件夹下,只需要将它们拖入工程就能直接使用。 54 | 55 | 当然,可以使用`-createFileWithName:data:path:`方法中的`path`指定工作空间的存储路径。 56 | 57 | ### 字典转模型框架设置 58 | 59 | 由于工具会自动进行属性和数组元素的映射,你需要指定工程使用的字典转模型框架,目前支持 YYModel 和 MJExtension。 60 | ```objc 61 | [YBMFConfig shareConfig].framework = YBMFFrameworkYY; 62 | ``` 63 | 64 | ### NSCoding 和 NSCopying 协议 65 | 66 | NSCoding 和 NSCopying 协议是否实现可以指定: 67 | ```objc 68 | [YBMFConfig shareConfig].needCoding = NO; 69 | [YBMFConfig shareConfig].needCopying = NO; 70 | ``` 71 | 72 | ### 属性和方法之间是否空行 73 | 74 | 工具提供简单的定制: 75 | ```objc 76 | [YBMFConfig shareConfig].fileHHandler.ybmf_skipLine = YES; 77 | [YBMFConfig shareConfig].fileMHandler.ybmf_skipLine = YES; 78 | ``` 79 | 80 | ### 类名公用后缀 81 | 82 | 默认情况下,类名公用后缀为`Model`,可以自行定制: 83 | ```objc 84 | [YBMFConfig shareConfig].fileSuffix = @"File"; 85 | ``` 86 | 87 | ### 属性忽略类型 88 | 89 | 在构建 Model 时,往往需要过滤掉一些类型,比如需要使用`NSString`提到`NSNumber`,过滤掉字典中的可变类型。这些都可以通过一个多选枚举来配置,过滤的类型工具会使用更宽泛的类型来处理。 90 | ```objc 91 | [YBMFConfig shareConfig].ignoreType = YBMFIgnoreTypeAllDigital | YBMFIgnoreTypeMutable; 92 | ``` 93 | 94 | ### 文件划分策略 95 | 96 | 目前支持两种策略,一种是所有类都放到一组文件 (.h/.m),一种是一个类对应一组文件: 97 | ```objc 98 | [YBMFConfig shareConfig].filePartitionMode = YBMFFilePartitionModeApart; 99 | ``` 100 | 101 | ### 处理算法自定义 102 | 103 | 对于工具中的算法,都是通过一些类来处理,默认有实现,如果需要自定义,只需要实现对应的协议并且赋值给配置单例: 104 | ```objc 105 | /** 名字处理器 */ 106 | @property (nonatomic, strong) id nameHander; 107 | /** 文件头部注解处理器 */ 108 | @property (nonatomic, strong) id fileNoteHander; 109 | /** .h文件代码处理器 */ 110 | @property (nonatomic, strong) id fileHHandler; 111 | /** .m文件代码处理器 */ 112 | @property (nonatomic, strong) id fileMHandler; 113 | /** 节点作为父节点的属性时 Code 格式处理器 */ 114 | @property (nonatomic, strong) id codeForParentHandler; 115 | ``` 116 | 117 | 118 | -------------------------------------------------------------------------------- /YBModelFile.podspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | Pod::Spec.new do |s| 4 | 5 | 6 | s.name = "YBModelFile" 7 | s.version = "1.0.3" 8 | s.summary = "iOS 效率工具:自动生成 Model 文件(数据模型) / iOS efficiency tool : create data model files automatically" 9 | s.description = <<-DESC 10 | iOS 效率工具:自动生成 Model 文件(数据模型) / iOS efficiency tool : create data model files automatically 11 | 只需传入一个 json 数据就能自动生成所需文件,拖入工程就能使用。 12 | DESC 13 | 14 | s.homepage = "https://github.com/indulgeIn" 15 | 16 | s.license = "MIT" 17 | 18 | s.author = { "杨波" => "1106355439@qq.com" } 19 | 20 | s.platform = :ios, "8.0" 21 | 22 | s.source = { :git => "https://github.com/indulgeIn/YBModelFile.git", :tag => "#{s.version}" } 23 | 24 | s.source_files = "YBModelFile/**/*.{h,m}" 25 | 26 | s.requires_arc = true 27 | 28 | end 29 | -------------------------------------------------------------------------------- /YBModelFile/Handler/YBMFCodeForParentHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // YBMFCodeForParentHandler.h 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/20. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YBMFNode.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @protocol YBMFCodeForParentHandler 15 | 16 | - (NSString *)ybmf_codeForParentWithNode:(YBMFNode *)node; 17 | 18 | @end 19 | 20 | @interface YBMFCodeForParentHandler : NSObject 21 | 22 | @end 23 | 24 | NS_ASSUME_NONNULL_END 25 | -------------------------------------------------------------------------------- /YBModelFile/Handler/YBMFCodeForParentHandler.m: -------------------------------------------------------------------------------- 1 | // 2 | // YBMFCodeForParentHandler.m 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/20. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import "YBMFCodeForParentHandler.h" 10 | 11 | @implementation YBMFCodeForParentHandler 12 | 13 | #pragma mark - 14 | 15 | - (NSString *)ybmf_codeForParentWithNode:(YBMFNode *)node { 16 | switch (node.type) { 17 | case YBMFNodeTypeBOOL: 18 | return @"@property (nonatomic, assign) BOOL "; 19 | case YBMFNodeTypeNSInteger: 20 | return @"@property (nonatomic, assign) NSInteger "; 21 | case YBMFNodeTypeDouble: 22 | return @"@property (nonatomic, assign) double "; 23 | case YBMFNodeTypeNSNumber: 24 | return @"@property (nonatomic, copy) NSNumber *"; 25 | case YBMFNodeTypeNSMutableString: 26 | return @"@property (nonatomic, strong) NSMutableString *"; 27 | case YBMFNodeTypeNSString: 28 | return @"@property (nonatomic, copy) NSString *"; 29 | case YBMFNodeTypeClass: 30 | return [NSString stringWithFormat:@"@property (nonatomic, strong) %@ *", node.className]; 31 | case YBMFNodeTypeNSMutableArray: { 32 | YBMFNode *child = node.children[YBMFNodeArrayElementKey]; 33 | if (child && child.className && child.className.length > 0) { 34 | return [NSString stringWithFormat:@"@property (nonatomic, strong) NSMutableArray<%@ *> *", child.className]; 35 | } else { 36 | return @"@property (nonatomic, strong) NSMutableArray *"; 37 | } 38 | } 39 | case YBMFNodeTypeNSArray: { 40 | YBMFNode *child = node.children[YBMFNodeArrayElementKey]; 41 | if (child && child.className && child.className.length > 0) { 42 | return [NSString stringWithFormat:@"@property (nonatomic, copy) NSArray<%@ *> *", child.className]; 43 | } else { 44 | return @"@property (nonatomic, copy) NSArray *"; 45 | } 46 | } 47 | default: 48 | return @""; 49 | } 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /YBModelFile/Handler/YBMFFileHHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // YBMFFileHHandler.h 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/20. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YBMFNode.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @protocol YBMFFileHHandler 15 | 16 | /** 属性之间是否空行 */ 17 | @property (nonatomic, assign) BOOL ybmf_skipLine; 18 | 19 | - (NSString *)ybmf_importInfoWithNode:(YBMFNode *)node withoutProperty:(BOOL)withoutProperty; 20 | 21 | - (NSString *)ybmf_codeInfoWithNode:(YBMFNode *)node; 22 | 23 | @end 24 | 25 | @interface YBMFFileHHandler : NSObject 26 | 27 | @end 28 | 29 | NS_ASSUME_NONNULL_END 30 | -------------------------------------------------------------------------------- /YBModelFile/Handler/YBMFFileHHandler.m: -------------------------------------------------------------------------------- 1 | // 2 | // YBMFFileHHandler.m 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/20. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import "YBMFFileHHandler.h" 10 | #import "NSObject+YBMFConfig.h" 11 | 12 | @interface YBMFFileHHandler () 13 | @property (nonatomic, strong) NSDictionary *frameworkMapper; 14 | @end 15 | 16 | @implementation YBMFFileHHandler 17 | 18 | @synthesize ybmf_skipLine = _ybmf_skipLine; 19 | 20 | #pragma mark - life cycle 21 | 22 | - (instancetype)init { 23 | self = [super init]; 24 | if (self) { 25 | self.ybmf_skipLine = NO; 26 | } 27 | return self; 28 | } 29 | 30 | #pragma mark - 31 | 32 | - (NSString *)ybmf_importInfoWithNode:(YBMFNode *)node withoutProperty:(BOOL)withoutProperty { 33 | NSMutableString *importInfo = [NSMutableString string]; 34 | 35 | //基类的依赖 36 | Class baseClass = self.ybmf_config.baseClass; 37 | NSBundle *baseClassBundle = [NSBundle bundleForClass:baseClass]; 38 | if (baseClassBundle == [NSBundle mainBundle]) { //自定义类 39 | [importInfo appendString:[NSString stringWithFormat:@"#import \"%@.h\"\n", NSStringFromClass(baseClass)]]; 40 | } else { //系统类 41 | NSString *lastPathComponent = baseClassBundle.bundlePath.lastPathComponent; 42 | NSString *framework = self.frameworkMapper[lastPathComponent]; 43 | if (!framework) framework = @"Foundation/Foundation.h"; 44 | [importInfo appendString:[NSString stringWithFormat:@"#import <%@>\n", framework]]; 45 | } 46 | 47 | if (withoutProperty) return importInfo; 48 | 49 | //属性的依赖 (该工具特殊性,除开自定义类,属性都在 Foundation/Foundation.h) 50 | [node.children enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, YBMFNode * _Nonnull obj, BOOL * _Nonnull stop) { 51 | NSString *customClassName; 52 | if (obj.type == YBMFNodeTypeNSArray) { 53 | YBMFNode *child = obj.children[YBMFNodeArrayElementKey]; 54 | if (child && child.type == YBMFNodeTypeClass) { 55 | customClassName = child.className; 56 | } 57 | } else if (obj.type == YBMFNodeTypeClass) { 58 | customClassName = obj.className; 59 | } 60 | if (customClassName && customClassName.length > 0) { 61 | [importInfo appendString:[NSString stringWithFormat:@"#import \"%@.h\"\n", customClassName]]; 62 | } 63 | }]; 64 | 65 | return importInfo; 66 | } 67 | 68 | - (NSString *)ybmf_codeInfoWithNode:(YBMFNode *)node { 69 | NSMutableString *codeInfo = [NSMutableString string]; 70 | 71 | [codeInfo appendString:[NSString stringWithFormat:@"@interface %@ : %@", node.className, NSStringFromClass(self.ybmf_config.baseClass)]]; 72 | 73 | NSMutableString *protocolStr = [NSMutableString string]; 74 | if (self.ybmf_config.needCopying) { 75 | if (protocolStr.length == 0) { 76 | [protocolStr appendString:@" 0) { 89 | [protocolStr appendString:@">\n"]; 90 | [codeInfo appendString:protocolStr]; 91 | } else { 92 | [codeInfo appendString:@"\n"]; 93 | } 94 | 95 | if (self.ybmf_skipLine) [codeInfo appendString:@"\n"]; 96 | [node.children enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, YBMFNode * _Nonnull obj, BOOL * _Nonnull stop) { 97 | NSString *codeForParent = [self.ybmf_config.codeForParentHandler ybmf_codeForParentWithNode:obj]; 98 | 99 | [codeInfo appendString:[NSString stringWithFormat:@"%@%@;", codeForParent, key]]; 100 | [codeInfo appendString:@"\n"]; 101 | if (self.ybmf_skipLine) [codeInfo appendString:@"\n"]; 102 | }]; 103 | 104 | [codeInfo appendString:@"@end\n"]; 105 | return codeInfo; 106 | } 107 | 108 | #pragma mark - getter 109 | 110 | - (NSDictionary *)frameworkMapper { 111 | if (!_frameworkMapper) { 112 | _frameworkMapper 113 | = @{@"lib":@"Foundation/Foundation.h", 114 | @"CoreFoundation.framework":@"Foundation/Foundation.h", 115 | @"UIKitCore.framework":@"UIKit/UIKit.h", 116 | @"QuartzCore.framework":@"QuartzCore/QuartzCore.h", 117 | @"Photos.framework":@"Photos/Photos.h", 118 | @"MapKit.framework":@"MapKit/MapKit.h", 119 | @"AddressBookUI.framework":@"AddressBookUI/AddressBookUI.h", 120 | @"Accounts.framework":@"Accounts/Accounts.h", 121 | @"ARKit.framework":@"ARKit/ARKit.h", 122 | @"AssetsLibrary.framework":@"AssetsLibrary/AssetsLibrary.h", 123 | @"AVFoundation.framework":@"AVFoundation/AVFoundation.h"}; 124 | } 125 | return _frameworkMapper; 126 | } 127 | 128 | @end 129 | -------------------------------------------------------------------------------- /YBModelFile/Handler/YBMFFileMHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // YBMFFileMHandler.h 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/20. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YBMFNode.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @protocol YBMFFileMHandler 15 | 16 | /** 方法之间是否空行 */ 17 | @property (nonatomic, assign) BOOL ybmf_skipLine; 18 | 19 | - (NSString *)ybmf_importInfoWithNode:(YBMFNode *)node; 20 | 21 | - (NSString *)ybmf_codeInfoWithNode:(YBMFNode *)node; 22 | 23 | @end 24 | 25 | @interface YBMFFileMHandler : NSObject 26 | 27 | @end 28 | 29 | NS_ASSUME_NONNULL_END 30 | -------------------------------------------------------------------------------- /YBModelFile/Handler/YBMFFileMHandler.m: -------------------------------------------------------------------------------- 1 | // 2 | // YBMFFileMHandler.m 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/20. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import "YBMFFileMHandler.h" 10 | #import "NSObject+YBMFConfig.h" 11 | 12 | @implementation YBMFFileMHandler 13 | 14 | @synthesize ybmf_skipLine = _ybmf_skipLine; 15 | 16 | #pragma mark - life cycle 17 | 18 | - (instancetype)init { 19 | self = [super init]; 20 | if (self) { 21 | self.ybmf_skipLine = NO; 22 | } 23 | return self; 24 | } 25 | 26 | #pragma mark - 27 | 28 | - (NSString *)ybmf_importInfoWithNode:(YBMFNode *)node { 29 | return [NSString stringWithFormat:@"#import \"%@.h\"\n", node.className]; 30 | } 31 | 32 | - (NSString *)ybmf_codeInfoWithNode:(YBMFNode *)node { 33 | NSMutableString *codeInfo = [NSMutableString string]; 34 | [codeInfo appendString:[NSString stringWithFormat:@"@implementation %@\n", node.className]]; 35 | if (self.ybmf_skipLine) [codeInfo appendString:@"\n"]; 36 | 37 | //实现属性映射 38 | if (node.propertyMapper.count > 0) { 39 | switch (self.ybmf_config.framework) { 40 | case YBMFFrameworkYY: [codeInfo appendString:@"+ (NSDictionary *)modelCustomPropertyMapper {\n"]; 41 | break; 42 | case YBMFFrameworkMJ: [codeInfo appendString:@"+ (NSDictionary *)mj_replacedKeyFromPropertyName {\n"]; 43 | break; 44 | default: break; 45 | } 46 | 47 | [codeInfo appendString:@" return @{"]; 48 | __block BOOL start = YES; 49 | [node.propertyMapper enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) { 50 | if (!start) [codeInfo appendString:@", "]; 51 | start = NO; 52 | [codeInfo appendString:[NSString stringWithFormat:@"@\"%@\":@\"%@\"", key, obj]]; 53 | }]; 54 | [codeInfo appendString:@"};"]; 55 | [codeInfo appendString:@"\n}\n"]; 56 | if (self.ybmf_skipLine) [codeInfo appendString:@"\n"]; 57 | } 58 | 59 | //实现容器元素映射 60 | if (node.containerMapper.count > 0) { 61 | switch (self.ybmf_config.framework) { 62 | case YBMFFrameworkYY: [codeInfo appendString:@"+ (NSDictionary *)modelContainerPropertyGenericClass {\n"]; 63 | break; 64 | case YBMFFrameworkMJ: [codeInfo appendString:@"+ (NSDictionary *)mj_objectClassInArray {\n"]; 65 | break; 66 | default: break; 67 | } 68 | 69 | [codeInfo appendString:@" return @{"]; 70 | __block BOOL start = YES; 71 | [node.containerMapper enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) { 72 | if (!start) [codeInfo appendString:@", "]; 73 | start = NO; 74 | [codeInfo appendString:[NSString stringWithFormat:@"@\"%@\":@\"%@\"", key, obj]]; 75 | }]; 76 | [codeInfo appendString:@"};"]; 77 | [codeInfo appendString:@"\n}\n"]; 78 | if (self.ybmf_skipLine) [codeInfo appendString:@"\n"]; 79 | } 80 | 81 | //实现 NSCopying 协议 82 | if (self.ybmf_config.needCopying) { 83 | [codeInfo appendString:@"- (id)copyWithZone:(NSZone *)zone {\n"]; 84 | [codeInfo appendString:@" typeof(self) one = [[[self class] allocWithZone:zone] init];\n"]; 85 | [node.children.allKeys enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 86 | [codeInfo appendString:[NSString stringWithFormat:@" one.%@ = self.%@;\n", obj, obj]]; 87 | }]; 88 | [codeInfo appendString:@" return one;\n}\n"]; 89 | if (self.ybmf_skipLine) [codeInfo appendString:@"\n"]; 90 | } 91 | 92 | //实现 NSCoding 协议 93 | if (self.ybmf_config.needCoding) { 94 | switch (self.ybmf_config.framework) { 95 | case YBMFFrameworkYY: { 96 | [codeInfo appendString: 97 | @"- (instancetype)initWithCoder:(NSCoder *)aDecoder {\n" 98 | " self = [self init];\n" 99 | " [self yy_modelInitWithCoder:aDecoder];\n" 100 | " return self;\n" 101 | "}\n"]; 102 | if (self.ybmf_skipLine) [codeInfo appendString:@"\n"]; 103 | [codeInfo appendString: 104 | @"- (void)encodeWithCoder:(NSCoder *)aCoder {\n" 105 | " [self yy_modelEncodeWithCoder:aCoder];\n" 106 | "}\n"]; 107 | } 108 | break; 109 | case YBMFFrameworkMJ: { 110 | [codeInfo appendString: 111 | @"- (instancetype)initWithCoder:(NSCoder *)aDecoder {\n" 112 | " self = [self init];\n" 113 | " [self mj_decode:aDecoder];\n" 114 | " return self;\n" 115 | "}\n"]; 116 | if (self.ybmf_skipLine) [codeInfo appendString:@"\n"]; 117 | [codeInfo appendString: 118 | @"- (void)encodeWithCoder:(NSCoder *)aCoder {\n" 119 | " [self mj_encode:aCoder];\n" 120 | "}\n"]; 121 | } 122 | break; 123 | default: break; 124 | } 125 | if (self.ybmf_skipLine) [codeInfo appendString:@"\n"]; 126 | } 127 | 128 | [codeInfo appendString:@"@end\n"]; 129 | return codeInfo; 130 | } 131 | 132 | @end 133 | -------------------------------------------------------------------------------- /YBModelFile/Handler/YBMFFileNoteHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // YBMFFileNoteHandler.h 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/19. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | typedef NS_ENUM(NSInteger, YBMFFileNoteType) { 14 | YBMFFileNoteTypeH, //.h文件 15 | YBMFFileNoteTypeM //.m文件 16 | }; 17 | 18 | @protocol YBMFFileNoteHandler 19 | 20 | /** 开发者 */ 21 | @property (nonatomic, copy) NSString *ybmf_developer; 22 | 23 | /** 组织 */ 24 | @property (nonatomic, copy) NSString *ybmf_organization; 25 | 26 | /** 工程名 (若该工具在当前工程运行,无需处理该值) */ 27 | @property (nonatomic, copy) NSString *ybmf_executableName; 28 | 29 | /** 30 | 获取文件头部注解 31 | 32 | @param fileName 文件名 33 | @param fileType 文件类型 34 | @return 注解 35 | */ 36 | - (NSString *)ybmf_fileNoteWithFileName:(NSString *)fileName fileType:(YBMFFileNoteType)fileType; 37 | 38 | @end 39 | 40 | @interface YBMFFileNoteHandler : NSObject 41 | 42 | @end 43 | 44 | NS_ASSUME_NONNULL_END 45 | -------------------------------------------------------------------------------- /YBModelFile/Handler/YBMFFileNoteHandler.m: -------------------------------------------------------------------------------- 1 | // 2 | // YBMFFileNoteHandler.m 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/19. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import "YBMFFileNoteHandler.h" 10 | 11 | @implementation YBMFFileNoteHandler 12 | 13 | @synthesize ybmf_developer = _ybmf_developer; 14 | @synthesize ybmf_organization = _ybmf_organization; 15 | @synthesize ybmf_executableName = _ybmf_executableName; 16 | 17 | #pragma mark - life cycle 18 | 19 | - (instancetype)init { 20 | self = [super init]; 21 | if (self) { 22 | self.ybmf_executableName = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleExecutableKey]; 23 | self.ybmf_developer = @"indulgeIn"; 24 | self.ybmf_organization = @"indulgeIn"; 25 | } 26 | return self; 27 | } 28 | 29 | #pragma mark - 30 | 31 | - (NSString *)ybmf_fileNoteWithFileName:(NSString *)fileName fileType:(YBMFFileNoteType)fileType { 32 | if (!fileName || fileName.length == 0) return @""; 33 | 34 | NSMutableString *fileNote = [NSMutableString string]; 35 | 36 | NSDate *date = NSDate.date; 37 | NSDateFormatter *format = NSDateFormatter.new; 38 | [format setDateFormat:@"yyyy/MM/dd"]; 39 | NSString *dateStr = [format stringFromDate:date]; 40 | NSDateFormatter *format1 = NSDateFormatter.new; 41 | [format1 setDateFormat:@"yyyy"]; 42 | NSString *dateYearStr = [format1 stringFromDate:date]; 43 | 44 | [fileNote appendString:@"//\n"]; 45 | [fileNote appendString:[NSString stringWithFormat:@"// %@%@\n", fileName, fileType == YBMFFileNoteTypeH ? @".h" : @".m"]]; 46 | [fileNote appendString:[NSString stringWithFormat:@"// %@\n", self.ybmf_executableName]]; 47 | [fileNote appendString:@"//\n"]; 48 | [fileNote appendString:[NSString stringWithFormat:@"// Created by %@ on %@.\n", self.ybmf_developer, dateStr]]; 49 | [fileNote appendString:[NSString stringWithFormat:@"// Copyright © %@ %@. All rights reserved.\n", dateYearStr, self.ybmf_organization]]; 50 | [fileNote appendString:@"//\n"]; 51 | 52 | return fileNote; 53 | } 54 | 55 | 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /YBModelFile/Handler/YBMFNameHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // YBMFNameHandler.h 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/19. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YBMFNode.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @protocol YBMFNameHandler 15 | 16 | /** 17 | 根据已知数据生成类名 18 | 19 | @param prefix 前缀字符串 (比如 YBGoodsModel) 20 | @param suffix 后缀字符串 (默认为 Model) 21 | @param key json 中的 key 22 | @return 类名 23 | */ 24 | - (NSString *)ybmf_classNameWithPrefix:(nullable NSString *)prefix suffix:(nullable NSString *)suffix key:(id)key; 25 | 26 | /** 27 | 根据已知数据生成属性名 28 | 29 | @param key json 中的 key 30 | @param existKeys 已经存在的 keys 31 | @return 属性名 32 | */ 33 | - (NSString *)ybmf_propertyNameWithKey:(id)key existKeys:(NSArray *)existKeys; 34 | 35 | /* 是否需要类名判重(默认为 NO) */ 36 | @property (nonatomic, assign) BOOL ybmf_shouldAvoidClassRepeat; 37 | 38 | @end 39 | 40 | /** 41 | 该类 ybmf_classNameWithPrefix:suffix:key 实现: 42 | 参数: prefix:YBGoodsModel suffix:Model key:price_info 43 | 输出: YBGoodsPriceInfoModel 44 | */ 45 | @interface YBMFNameHandler : NSObject 46 | 47 | @end 48 | 49 | NS_ASSUME_NONNULL_END 50 | -------------------------------------------------------------------------------- /YBModelFile/Handler/YBMFNameHandler.m: -------------------------------------------------------------------------------- 1 | // 2 | // YBMFNameHandler.m 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/19. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import "YBMFNameHandler.h" 10 | #import 11 | #import "YBMFConfig.h" 12 | 13 | 14 | //命名非法字符 15 | static BOOL YBCharIsIllegal(char c) { 16 | return !((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_'); 17 | } 18 | 19 | //过滤非法字符 (用'_') 20 | static NSString *YBFilterIllegalChar(NSString *string) { 21 | NSMutableString *res = [NSMutableString string]; 22 | for(int i = 0; i < string.length; ++i){ 23 | unichar c = [string characterAtIndex:i]; 24 | [res appendString:YBCharIsIllegal(c) ? @"_" : [NSString stringWithFormat:@"%c", c]]; 25 | } 26 | return res; 27 | } 28 | 29 | //指定大写范围 30 | static NSString *YBSpecifyCapitalizeWithString(NSString *string, NSUInteger length) { 31 | if (!string || string.length == 0) return string; 32 | if (string.length < length) length = string.length; 33 | return [string stringByReplacingCharactersInRange:NSMakeRange(0, length) withString:[[string substringToIndex:length] capitalizedString]]; 34 | } 35 | 36 | //全大写 37 | static NSString *YBCapitalizeWithString(NSString *string) { 38 | if (!string || string.length == 0) return string; 39 | return [string capitalizedString]; 40 | } 41 | 42 | //驼峰命名 43 | static NSString *YBCamelCaseWithString(NSString *string) { 44 | if (!string || string.length == 0) return string; 45 | 46 | NSMutableString *res = [NSMutableString stringWithString:@""]; 47 | NSScanner *scanner = [NSScanner scannerWithString:string]; 48 | while (true) { 49 | NSString *tmp; 50 | BOOL scan = [scanner scanUpToString:@"_" intoString:&tmp]; 51 | if (scan && tmp) { 52 | [res appendString:YBSpecifyCapitalizeWithString(tmp, 1)]; 53 | } 54 | if ([scanner isAtEnd]) break; 55 | ++scanner.scanLocation; 56 | } 57 | return res; 58 | } 59 | 60 | //属性名保留字 61 | static NSSet *YBPropertyReservedWord(void) { 62 | static NSSet *set = nil; 63 | static dispatch_once_t onceToken; 64 | dispatch_once(&onceToken, ^{ 65 | set = [NSSet setWithObjects: 66 | @"if", @"else", @"switch", @"case", @"do", @"while", @"return", @"break", 67 | @"true", @"false", @"YES", @"NO", 68 | @"char", @"short", @"int", @"long", @"double", @"float", 69 | @"struct", @"static", nil]; 70 | }); 71 | return set; 72 | } 73 | 74 | //属性名非法字符前缀 75 | static NSSet *YBPropertyIllegalCharPrefix(void) { 76 | static NSSet *set = nil; 77 | static dispatch_once_t onceToken; 78 | dispatch_once(&onceToken, ^{ 79 | set = [NSSet setWithObjects: 80 | @"new", @"init", nil]; 81 | }); 82 | return set; 83 | } 84 | 85 | //属性名非法数字前缀 86 | static NSSet *YBPropertyIllegalNumberPrefix(void) { 87 | static NSSet *set = nil; 88 | static dispatch_once_t onceToken; 89 | dispatch_once(&onceToken, ^{ 90 | set = [NSSet setWithObjects: 91 | @"0", @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", nil]; 92 | }); 93 | return set; 94 | } 95 | 96 | static NSSet *YBClassVarsExceptPrefix(Class cls) { 97 | static NSMutableDictionary *dic = nil; 98 | static dispatch_once_t onceToken; 99 | dispatch_once(&onceToken, ^{ 100 | dic = [NSMutableDictionary dictionary]; 101 | }); 102 | 103 | NSString *key = NSStringFromClass(cls); 104 | if (dic[key]) return dic[key]; 105 | 106 | //TODO 本身这里需要查询每一个层级类的协议属性,为了简便直接加上 NSObject 协议的实例变量。 107 | NSMutableSet *set = [NSMutableSet setWithObjects:@"description", @"debugDescription", @"superclass", @"hash", nil]; 108 | 109 | Class cCls = cls; 110 | while (cCls) { 111 | unsigned int ivarCount = 0; 112 | Ivar *ivars = class_copyIvarList(cCls, &ivarCount); 113 | for (unsigned int i = 0; i < ivarCount; ++i) { 114 | Ivar ivar = ivars[i]; 115 | NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)]; 116 | if ([ivarName hasPrefix:@"_"]) ivarName = [ivarName substringWithRange:NSMakeRange(1, ivarName.length - 1)]; 117 | [set addObject:ivarName]; 118 | } 119 | free(ivars); 120 | cCls = class_getSuperclass(cCls); 121 | } 122 | 123 | dic[key] = set; 124 | return set; 125 | } 126 | 127 | 128 | @interface YBMFNameHandler () 129 | @property (nonatomic, strong) NSMutableSet *classNames; 130 | @end 131 | 132 | @implementation YBMFNameHandler 133 | 134 | #pragma mark - 135 | 136 | @synthesize ybmf_shouldAvoidClassRepeat = _ybmf_shouldAvoidClassRepeat; 137 | 138 | - (NSString *)ybmf_classNameWithPrefix:(NSString *)prefix suffix:(NSString *)suffix key:(id)key { 139 | NSString *keyStr = [NSString stringWithFormat:@"%@", key]; 140 | if (!keyStr) keyStr = @""; 141 | if (!suffix) suffix = @""; 142 | if (!prefix) prefix = @""; 143 | if ([prefix hasSuffix:suffix]) { 144 | //去掉 suffix 后缀 145 | prefix = [prefix stringByReplacingOccurrencesOfString:suffix withString:@""]; 146 | } 147 | 148 | //过滤关键字 149 | keyStr = YBFilterIllegalChar(keyStr); 150 | 151 | //驼峰命名 152 | keyStr = YBCamelCaseWithString(keyStr); 153 | 154 | //类名判重 155 | NSString *tmp = [NSString stringWithFormat:@"%@%@%@", prefix, keyStr, suffix]; 156 | if (self.ybmf_shouldAvoidClassRepeat) { 157 | NSUInteger suf = 0; 158 | while (NSClassFromString(tmp) && ![self.classNames containsObject:tmp]) { 159 | tmp = [NSString stringWithFormat:@"%@%@", prefix, keyStr]; 160 | tmp = [tmp stringByAppendingString:[NSString stringWithFormat:@"%lu", (unsigned long)++suf]]; 161 | tmp = [tmp stringByAppendingString:suffix]; 162 | } 163 | } 164 | [self.classNames addObject:tmp]; 165 | return tmp; 166 | } 167 | 168 | - (NSString *)ybmf_propertyNameWithKey:(id)key existKeys:(nonnull NSArray *)existKeys { 169 | __block NSString *keyStr = [NSString stringWithFormat:@"%@", key]; 170 | if (!keyStr) return @""; 171 | 172 | //过滤非法字符 173 | keyStr = YBFilterIllegalChar(keyStr); 174 | 175 | //如果是保留字,全大写 176 | if ([YBPropertyReservedWord() containsObject:keyStr]) { 177 | keyStr = YBCapitalizeWithString(keyStr); 178 | } 179 | 180 | //前缀有保留字,保留字部分大写 181 | [YBPropertyIllegalCharPrefix() enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, BOOL * _Nonnull stop) { 182 | if ([keyStr hasPrefix:obj]) { 183 | keyStr = YBSpecifyCapitalizeWithString(keyStr, obj.length); 184 | *stop = YES; 185 | } 186 | }]; 187 | 188 | //前缀是数字,拼接一个下划线 189 | if ([YBPropertyIllegalNumberPrefix() containsObject:[keyStr substringToIndex:1]]) { 190 | keyStr = [@"_" stringByAppendingString:keyStr]; 191 | } 192 | 193 | //属性名判重 194 | NSString *tmp = keyStr.copy; 195 | NSUInteger suf = 0; 196 | NSSet *illegalVars = YBClassVarsExceptPrefix([YBMFConfig shareConfig].baseClass); 197 | while ([existKeys containsObject:tmp] || [illegalVars containsObject:tmp]) { 198 | tmp = keyStr.copy; 199 | tmp = [tmp stringByAppendingString:[NSString stringWithFormat:@"%lu", (unsigned long)++suf]]; 200 | } 201 | return tmp; 202 | } 203 | 204 | #pragma mark - getter 205 | 206 | - (NSMutableSet *)classNames { 207 | if (!_classNames) { 208 | _classNames = [NSMutableSet set]; 209 | } 210 | return _classNames; 211 | } 212 | 213 | @end 214 | -------------------------------------------------------------------------------- /YBModelFile/Helper/NSObject+YBMFConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+YBMFConfig.h 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/4/25. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YBMFConfig.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface NSObject (YBMFConfig) 15 | 16 | @property (nonatomic, weak) YBMFConfig *ybmf_config; 17 | 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /YBModelFile/Helper/NSObject+YBMFConfig.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+YBMFConfig.m 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/4/25. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import "NSObject+YBMFConfig.h" 10 | #import 11 | 12 | static const void *configKey = &configKey; 13 | 14 | @implementation NSObject (YBMFConfig) 15 | 16 | - (void)setYbmf_config:(YBMFConfig *)ybmf_config { 17 | objc_setAssociatedObject(self, configKey, ybmf_config, OBJC_ASSOCIATION_ASSIGN); 18 | } 19 | 20 | - (YBMFConfig *)ybmf_config { 21 | return objc_getAssociatedObject(self, configKey); 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /YBModelFile/Node/YBMFNode.h: -------------------------------------------------------------------------------- 1 | // 2 | // YBMFNode.h 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/18. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | extern NSString * const YBMFNodeArrayElementKey; 14 | 15 | typedef NS_ENUM(NSInteger, YBMFNodeType) { 16 | YBMFNodeTypeUnknown, 17 | YBMFNodeTypeNSString, 18 | YBMFNodeTypeNSMutableString, 19 | YBMFNodeTypeBOOL, 20 | YBMFNodeTypeDouble, 21 | YBMFNodeTypeNSInteger, 22 | YBMFNodeTypeNSNumber, 23 | YBMFNodeTypeNSArray, 24 | YBMFNodeTypeNSMutableArray, 25 | YBMFNodeTypeClass 26 | }; 27 | 28 | @interface YBMFNode : NSObject 29 | 30 | /** 节点类型 */ 31 | @property (nonatomic, assign) YBMFNodeType type; 32 | 33 | /** 子节点 */ 34 | @property (nonatomic, strong) NSMutableDictionary *children; 35 | 36 | /** 节点类名 */ 37 | @property (nonatomic, copy) NSString *className; 38 | 39 | #pragma - 以下内容仅在 type == YBMFNodeTypeClass 时有用 40 | 41 | /** 属性映射 (属性名:字典中取值用的key) */ 42 | @property (nonatomic, strong) NSMutableDictionary *propertyMapper; 43 | 44 | /** 容器元素映射 (数组属性名:Class字符串) */ 45 | @property (nonatomic, strong) NSMutableDictionary *containerMapper; 46 | 47 | @end 48 | 49 | NS_ASSUME_NONNULL_END 50 | -------------------------------------------------------------------------------- /YBModelFile/Node/YBMFNode.m: -------------------------------------------------------------------------------- 1 | // 2 | // YBMFNode.m 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/18. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import "YBMFNode.h" 10 | 11 | NSString * const YBMFNodeArrayElementKey = @"kYBMFNodeArrayElementName"; 12 | 13 | @implementation YBMFNode 14 | 15 | #pragma mark - setter 16 | 17 | - (void)setType:(YBMFNodeType)type { 18 | _type = type; 19 | 20 | switch (type) { 21 | case YBMFNodeTypeNSNumber: 22 | self.className = NSStringFromClass(NSNumber.self); 23 | break; 24 | case YBMFNodeTypeNSString: 25 | self.className = NSStringFromClass(NSString.self); 26 | break; 27 | case YBMFNodeTypeNSMutableString: 28 | self.className = NSStringFromClass(NSMutableString.self); 29 | break; 30 | case YBMFNodeTypeNSArray: 31 | self.className = NSStringFromClass(NSArray.self); 32 | break; 33 | case YBMFNodeTypeNSMutableArray: 34 | self.className = NSStringFromClass(NSMutableArray.self); 35 | break; 36 | default: 37 | break; 38 | } 39 | } 40 | 41 | #pragma mark - getter 42 | 43 | - (NSMutableDictionary *)children { 44 | if (!_children) { 45 | _children = [NSMutableDictionary dictionary]; 46 | } 47 | return _children; 48 | } 49 | 50 | - (NSMutableDictionary *)propertyMapper { 51 | if (!_propertyMapper) { 52 | _propertyMapper = [NSMutableDictionary dictionary]; 53 | } 54 | return _propertyMapper; 55 | } 56 | 57 | - (NSMutableDictionary *)containerMapper { 58 | if (!_containerMapper) { 59 | _containerMapper = [NSMutableDictionary dictionary]; 60 | } 61 | return _containerMapper; 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /YBModelFile/YBMFConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // YBMFConfig.h 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/19. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YBMFNameHandler.h" 11 | #import "YBMFFileNoteHandler.h" 12 | #import "YBMFFileHHandler.h" 13 | #import "YBMFFileMHandler.h" 14 | #import "YBMFCodeForParentHandler.h" 15 | 16 | NS_ASSUME_NONNULL_BEGIN 17 | 18 | typedef NS_OPTIONS(NSUInteger, YBMFIgnoreType) { 19 | YBMFIgnoreTypeNone = 0, 20 | YBMFIgnoreTypeDouble = 1 << 0, 21 | YBMFIgnoreTypeNSInteger = 1 << 1, 22 | YBMFIgnoreTypeBOOL = 1 << 2, 23 | YBMFIgnoreTypeNSNumber = 1 << 3, 24 | YBMFIgnoreTypeAllDigital = YBMFIgnoreTypeDouble | YBMFIgnoreTypeNSInteger | YBMFIgnoreTypeBOOL | YBMFIgnoreTypeNSNumber, 25 | YBMFIgnoreTypeMutable = 1 << 4 //过滤掉可变类型 26 | }; 27 | 28 | typedef NS_ENUM(NSInteger, YBMFFramework) { 29 | YBMFFrameworkYY, //YYModel 30 | YBMFFrameworkMJ, //MJExtension 31 | YBMFFrameworkNone //此情况 .m 文件将不做映射处理 (谨慎使用) 32 | }; 33 | 34 | typedef NS_ENUM(NSInteger, YBMFFilePartitionMode) { 35 | YBMFFilePartitionModeApart, //一个类一组文件 36 | YBMFFilePartitionModeTogether, //多个类合并为一组文件 37 | }; 38 | 39 | @interface YBMFConfig : NSObject 40 | 41 | /** 42 | 全局配置单例(优先级低于单独配置的 YBMFConfig) 43 | 44 | @return YBMFConfig 45 | */ 46 | + (instancetype)shareConfig; 47 | 48 | /** 49 | 默认初始化方法 50 | 51 | @return YBMFConfig 52 | */ 53 | + (instancetype)defaultConfig; 54 | 55 | /** 文件名的后缀 (默认为 Model) */ 56 | @property (nonatomic, copy) NSString *fileSuffix; 57 | 58 | /** 文件分割模式 (默认为 YBMFFilePartitionModeApart) */ 59 | @property (nonatomic, assign) YBMFFilePartitionMode filePartitionMode; 60 | 61 | /** 类属性忽略的类型(内部自动用更通用类型替代, 默认为 YBMFIgnoreTypeMutable) */ 62 | @property (nonatomic, assign) YBMFIgnoreType ignoreType; 63 | 64 | /** 工程使用的 json 转 model 框架 (默认为 YBMFFrameworkYY) */ 65 | @property (nonatomic, assign) YBMFFramework framework; 66 | 67 | /** 是否需要实现 NSCopying 协议 (默认为 YES) */ 68 | @property (nonatomic, assign) BOOL needCopying; 69 | 70 | /** 是否需要实现 NSCoding 协议 (默认为 YES) */ 71 | @property (nonatomic, assign) BOOL needCoding; 72 | 73 | /** 数据模型类的统一基类 (默认为 NSObject) */ 74 | @property (nonatomic, strong) Class baseClass; 75 | 76 | /** 名字处理器 */ 77 | @property (nonatomic, strong) id nameHander; 78 | 79 | /** 文件头部注解处理器 */ 80 | @property (nonatomic, strong) id fileNoteHander; 81 | 82 | /** .h文件代码处理器 */ 83 | @property (nonatomic, strong) id fileHHandler; 84 | 85 | /** .m文件代码处理器 */ 86 | @property (nonatomic, strong) id fileMHandler; 87 | 88 | /** 节点作为父节点的属性时 Code 格式处理器 */ 89 | @property (nonatomic, strong) id codeForParentHandler; 90 | 91 | 92 | - (instancetype)init OBJC_UNAVAILABLE("use '+shareConfig:' instead"); 93 | + (instancetype)new OBJC_UNAVAILABLE("use '+shareConfig:' instead"); 94 | 95 | @end 96 | 97 | NS_ASSUME_NONNULL_END 98 | -------------------------------------------------------------------------------- /YBModelFile/YBMFConfig.m: -------------------------------------------------------------------------------- 1 | // 2 | // YBMFConfig.m 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/19. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import "YBMFConfig.h" 10 | #import "NSObject+YBMFConfig.h" 11 | 12 | @implementation YBMFConfig 13 | 14 | //test 15 | - (void)dealloc { 16 | NSLog(@"释放:%@", self); 17 | } 18 | 19 | + (instancetype)shareConfig { 20 | #if DEBUG 21 | static YBMFConfig *config = nil; 22 | static dispatch_once_t onceToken; 23 | dispatch_once(&onceToken, ^{ 24 | config = [[YBMFConfig alloc] initDefaults]; 25 | }); 26 | return config; 27 | #else 28 | return nil; 29 | #endif 30 | } 31 | 32 | + (instancetype)defaultConfig { 33 | YBMFConfig *config = [[YBMFConfig alloc] initDefaults]; 34 | return config; 35 | } 36 | 37 | - (instancetype)initDefaults { 38 | self = [super init]; 39 | if (self) { 40 | _fileSuffix = @"Model"; 41 | _filePartitionMode = YBMFFilePartitionModeTogether; 42 | _ignoreType = YBMFIgnoreTypeAllDigital | YBMFIgnoreTypeMutable; 43 | _baseClass = NSObject.self; 44 | _framework = YBMFFrameworkYY; 45 | _needCopying = YES; 46 | _needCoding = YES; 47 | _nameHander = [YBMFNameHandler new]; 48 | _fileNoteHander = [YBMFFileNoteHandler new]; 49 | 50 | YBMFFileHHandler *fileH = [YBMFFileHHandler new]; 51 | fileH.ybmf_config = self; 52 | _fileHHandler = fileH; 53 | 54 | YBMFFileMHandler *fileM = [YBMFFileMHandler new]; 55 | fileM.ybmf_config = self; 56 | _fileMHandler = fileM; 57 | 58 | _codeForParentHandler = [YBMFCodeForParentHandler new]; 59 | } 60 | return self; 61 | } 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /YBModelFile/YBModelFile.h: -------------------------------------------------------------------------------- 1 | // 2 | // YBModelFile.h 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/18. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YBMFConfig.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface YBModelFile : NSObject 15 | 16 | + (void)createFileWithName:(NSString *)name data:(id)data; 17 | 18 | + (void)createFileWithName:(NSString *)name data:(id)data config:(YBMFConfig *)config; 19 | 20 | /** 21 | 生成 Model 文件 22 | 23 | @param name 主 Model 文件名 24 | @param data 数据源 (字典/数组/json数据/json字符串/json文件名) 25 | @param config 配置 (默认为 [YBMFConfig shareConfig]) 26 | @param path 文件生成路径 (默认为桌面 YBModelFile-Workspace 文件夹) 27 | */ 28 | + (void)createFileWithName:(NSString *)name data:(id)data config:(nullable YBMFConfig *)config path:(nullable NSString *)path ; 29 | 30 | @end 31 | 32 | NS_ASSUME_NONNULL_END 33 | -------------------------------------------------------------------------------- /YBModelFile/YBModelFile.m: -------------------------------------------------------------------------------- 1 | // 2 | // YBModelFile.m 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/18. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import "YBModelFile.h" 10 | #import "YBMFNode.h" 11 | #import "YBMFNameHandler.h" 12 | 13 | @interface YBModelFile () 14 | @property (nonatomic, strong) YBMFNode *rootNode; 15 | @property (nonatomic, strong) YBMFConfig *config; 16 | @end 17 | 18 | @implementation YBModelFile 19 | 20 | #pragma mark - public 21 | 22 | + (void)createFileWithName:(NSString *)name data:(id)data { 23 | [self createFileWithName:name data:data config:nil path:nil]; 24 | } 25 | 26 | + (void)createFileWithName:(NSString *)name data:(id)data config:(YBMFConfig *)config { 27 | [self createFileWithName:name data:data config:config path:nil]; 28 | } 29 | 30 | + (void)createFileWithName:(NSString *)name data:(id)data config:(nullable YBMFConfig *)config path:(nullable NSString *)path { 31 | #if DEBUG 32 | if (!TARGET_IPHONE_SIMULATOR) { 33 | NSAssert(0, @"请用模拟器运行"); 34 | } 35 | [self private_createFileWithName:name data:data config:config path:path]; 36 | #endif 37 | } 38 | 39 | + (void)private_createFileWithName:(NSString *)name data:(id)data config:(nullable YBMFConfig *)config path:(nullable NSString *)path { 40 | if (!name || !data) goto fail; 41 | 42 | if ([data isKindOfClass:NSString.class]) { 43 | if ([data containsString:@":"]) { 44 | data = [data dataUsingEncoding:NSUTF8StringEncoding]; 45 | } else { 46 | NSString *path = [[NSBundle mainBundle] pathForResource:[data stringByDeletingPathExtension] ofType:@"json"]; 47 | data = [NSData dataWithContentsOfFile:path]; 48 | } 49 | if (!data) goto fail; 50 | } 51 | if ([data isKindOfClass:NSData.class]) { 52 | data = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; 53 | if (!data) goto fail; 54 | } 55 | if ([data isKindOfClass:NSArray.class] && ((NSArray *)data).count > 0) { 56 | data = ((NSArray *)data).firstObject; 57 | if (!data) goto fail; 58 | } 59 | if ([data isKindOfClass:NSDictionary.class]) { 60 | YBModelFile *mfile = YBModelFile.new; 61 | mfile.config = config ?: [YBMFConfig shareConfig]; 62 | mfile.rootNode = [mfile buildTreeWithParentClassName:nil key:name value:data]; 63 | [mfile creatWithPath:path]; 64 | } else { 65 | goto fail; 66 | } 67 | 68 | return; 69 | fail: 70 | NSAssert(0, @"json数据无效"); 71 | } 72 | 73 | //test 74 | - (void)dealloc { 75 | NSLog(@"释放:%@", self); 76 | } 77 | 78 | #pragma mark - build tree 79 | 80 | - (YBMFNode *)buildTreeWithParentClassName:(NSString *)parentClassName key:(id)key value:(id)value { 81 | if (!value) return nil; 82 | if (!key) key = @""; 83 | if (!parentClassName) parentClassName = @""; 84 | 85 | YBMFNode *node = YBMFNode.new; 86 | 87 | YBMFIgnoreType ignoreType = self.config.ignoreType; 88 | 89 | if ([value isKindOfClass:NSDictionary.class]) { 90 | 91 | node.type = YBMFNodeTypeClass; 92 | node.className = [self.config.nameHander ybmf_classNameWithPrefix:parentClassName suffix:self.config.fileSuffix key:key]; 93 | [((NSDictionary *)value) enumerateKeysAndObjectsUsingBlock:^(id _Nonnull _key, id _Nonnull _value, BOOL * _Nonnull stop) { 94 | 95 | NSString *n_key = [self.config.nameHander ybmf_propertyNameWithKey:_key existKeys:node.children.allKeys]; 96 | //添加属性映射 97 | if (![n_key isEqualToString:[NSString stringWithFormat:@"%@", _key]]) { 98 | node.propertyMapper[n_key] = [NSString stringWithFormat:@"%@", _key]; 99 | } 100 | 101 | YBMFNode *child = [self buildTreeWithParentClassName:node.className key:_key value:_value]; 102 | if (child.type == YBMFNodeTypeNSArray) { 103 | YBMFNode *ele = child.children[YBMFNodeArrayElementKey]; 104 | //添加容器元素映射 105 | if (ele && ele.type == YBMFNodeTypeClass) { 106 | node.containerMapper[n_key] = ele.className; 107 | } 108 | } 109 | node.children[n_key] = child; 110 | }]; 111 | 112 | } else if ([value isKindOfClass:NSArray.class]) { 113 | 114 | if (!(ignoreType & YBMFIgnoreTypeMutable) && [value isKindOfClass:NSMutableArray.class]) { 115 | node.type = YBMFNodeTypeNSMutableArray; 116 | } else { 117 | node.type = YBMFNodeTypeNSArray; 118 | } 119 | 120 | if (((NSArray *)value).count > 0) { 121 | YBMFNode *child = [self buildTreeWithParentClassName:parentClassName key:key value:((NSArray *)value).firstObject]; 122 | node.children[YBMFNodeArrayElementKey] = child; 123 | } 124 | 125 | } else if ([value isKindOfClass:NSString.class]) { 126 | 127 | if (!(ignoreType & YBMFIgnoreTypeMutable) && [value isKindOfClass:NSMutableString.class]) { 128 | node.type = YBMFNodeTypeNSMutableString; 129 | } else { 130 | node.type = YBMFNodeTypeNSString; 131 | } 132 | 133 | } else if ([value isKindOfClass:NSNumber.class]) { 134 | 135 | if ([value isKindOfClass:NSDecimalNumber.class]) { //优先处理超长数字 136 | node.type = YBMFNodeTypeNSString; 137 | } else if (!(ignoreType & YBMFIgnoreTypeBOOL) && [NSStringFromClass([value class]) isEqualToString:@"__NSCFBoolean"]) { 138 | node.type = YBMFNodeTypeBOOL; 139 | } else if (!(ignoreType & YBMFIgnoreTypeNSInteger) && strcmp([value objCType], "q") == 0) { 140 | node.type = YBMFNodeTypeNSInteger; 141 | } else if (!(ignoreType & YBMFIgnoreTypeDouble) && strcmp([value objCType], "d") == 0) { 142 | node.type = YBMFNodeTypeDouble; 143 | } else if (!(ignoreType & YBMFNodeTypeNSNumber)) { 144 | node.type = YBMFNodeTypeNSNumber; 145 | } else { 146 | node.type = YBMFNodeTypeNSString; 147 | } 148 | 149 | } else if ([value isKindOfClass:NSNull.class]) { 150 | node.type = YBMFNodeTypeNSString; 151 | } 152 | return node; 153 | } 154 | 155 | #pragma mark - create file 156 | 157 | - (void)creatWithPath:(NSString *)path { 158 | if (!path) { 159 | //找到桌面路径 160 | NSString *bundle = [[NSBundle mainBundle] resourcePath]; 161 | if (!bundle) NSAssert(0, @"自动获取桌面路径失败,请尝试添加文件路径"); 162 | path = [[bundle substringToIndex:[bundle rangeOfString:@"Library"].location] stringByAppendingFormat:@"Desktop"]; 163 | if (!path) NSAssert(0, @"自动获取桌面路径失败,请尝试添加文件路径"); 164 | } 165 | 166 | //创建一个工具工作空间 167 | NSString *rootDirectoryPath = [self creatDirectoryWithPath:path.copy directoryName:@"YBModelFile-Workspace" cover:YES]; 168 | 169 | //创建存放当前 json 模型文件的文件夹 170 | NSString *fileDirectoryPath = [self creatDirectoryWithPath:rootDirectoryPath.copy directoryName:self.rootNode.className cover:NO]; 171 | 172 | NSLog(@"\n✨✨ YBModelFile ✨✨\n生成文件目录:\n%@", fileDirectoryPath); 173 | 174 | [self creatFilesWithDirectoryPath:fileDirectoryPath]; 175 | } 176 | 177 | - (NSString *)creatDirectoryWithPath:(NSString *)path directoryName:(NSString *)directoryName cover:(BOOL)cover { 178 | NSString *directoryPath = [path stringByAppendingPathComponent:directoryName]; 179 | BOOL exist = [[NSFileManager defaultManager] fileExistsAtPath:directoryPath]; 180 | if (exist && cover) return directoryPath; 181 | NSUInteger suffix = 0; 182 | while (exist) { 183 | directoryPath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"%@%lu", directoryName, (unsigned long)++suffix]]; 184 | exist = [[NSFileManager defaultManager] fileExistsAtPath:directoryPath]; 185 | } 186 | NSError *error; 187 | BOOL creatDirSuccess = [[NSFileManager defaultManager] createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:&error]; 188 | if (!creatDirSuccess) NSAssert(0, error.description); 189 | return directoryPath; 190 | } 191 | 192 | - (NSString *)creatFileWithPath:(NSString *)path fileName:(NSString *)fileName fileCode:(NSString *)fileCode { 193 | NSString *filePath = [path stringByAppendingPathComponent:fileName]; 194 | NSError *error; 195 | BOOL creatFileSuccess = [fileCode writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:&error]; 196 | if (!creatFileSuccess) { 197 | NSLog(@"\n✨✨ YBModelFile ✨✨\n生成文件失败:\n%@", error.description); 198 | return nil; 199 | } else { 200 | return filePath; 201 | } 202 | } 203 | 204 | - (void)creatFilesWithDirectoryPath:(NSString *)path { 205 | switch (self.config.filePartitionMode) { 206 | case YBMFFilePartitionModeApart: 207 | [self dfs_creatFilesWithDirectoryPath:path node:self.rootNode]; 208 | break; 209 | case YBMFFilePartitionModeTogether: { 210 | 211 | NSMutableString *allInfoInFileH = [NSMutableString string]; 212 | NSMutableString *allInfoInFileM = [NSMutableString string]; 213 | 214 | NSMutableString *codeInFileH = [NSMutableString string]; 215 | NSMutableString *codeInFileM = [NSMutableString string]; 216 | [self dfs_mergeWithCodeInFileH:codeInFileH codeInFileM:codeInFileM node:self.rootNode]; 217 | 218 | [allInfoInFileH appendString:[self.config.fileNoteHander ybmf_fileNoteWithFileName:self.rootNode.className fileType:YBMFFileNoteTypeH]]; 219 | [allInfoInFileH appendString:@"\n"]; 220 | [allInfoInFileH appendString:[self.config.fileHHandler ybmf_importInfoWithNode:self.rootNode withoutProperty:YES]]; 221 | [allInfoInFileH appendString:@"\n"]; 222 | [allInfoInFileH appendString:@"NS_ASSUME_NONNULL_BEGIN\n\n\n"]; 223 | [allInfoInFileH appendString:codeInFileH]; 224 | [allInfoInFileH appendString:@"NS_ASSUME_NONNULL_END\n"]; 225 | 226 | [allInfoInFileM appendString:[self.config.fileNoteHander ybmf_fileNoteWithFileName:self.rootNode.className fileType:YBMFFileNoteTypeM]]; 227 | [allInfoInFileM appendString:@"\n"]; 228 | [allInfoInFileM appendString:[self.config.fileMHandler ybmf_importInfoWithNode:self.rootNode]]; 229 | [allInfoInFileM appendString:@"\n\n"]; 230 | [allInfoInFileM appendString:codeInFileM]; 231 | 232 | [self creatFileWithPath:path fileName:[NSString stringWithFormat:@"%@.h", self.rootNode.className] fileCode:allInfoInFileH]; 233 | [self creatFileWithPath:path fileName:[NSString stringWithFormat:@"%@.m", self.rootNode.className] fileCode:allInfoInFileM]; 234 | } 235 | default: 236 | break; 237 | } 238 | } 239 | 240 | - (void)dfs_creatFilesWithDirectoryPath:(NSString *)path node:(YBMFNode *)node { 241 | [node.children enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, YBMFNode * _Nonnull obj, BOOL * _Nonnull stop) { 242 | if (obj.type == YBMFNodeTypeClass) { 243 | [self dfs_creatFilesWithDirectoryPath:path node:obj]; 244 | } else if (obj.type == YBMFNodeTypeNSArray || obj.type == YBMFNodeTypeNSMutableArray) { 245 | YBMFNode *child = obj.children[YBMFNodeArrayElementKey]; 246 | if (child && child.type == YBMFNodeTypeClass) { 247 | [self dfs_creatFilesWithDirectoryPath:path node:child]; 248 | } 249 | } 250 | }]; 251 | [self creatFileWithPath:path fileName:[NSString stringWithFormat:@"%@.h", node.className] fileCode:[self allInfoFileH:node]]; 252 | [self creatFileWithPath:path fileName:[NSString stringWithFormat:@"%@.m", node.className] fileCode:[self allInfoFileM:node]]; 253 | } 254 | 255 | - (void)dfs_mergeWithCodeInFileH:(NSMutableString *)codeInFileH codeInFileM:(NSMutableString *)codeInFileM node:(YBMFNode *)node { 256 | [node.children enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, YBMFNode * _Nonnull obj, BOOL * _Nonnull stop) { 257 | if (obj.type == YBMFNodeTypeClass) { 258 | [self dfs_mergeWithCodeInFileH:codeInFileH codeInFileM:codeInFileM node:obj]; 259 | } else if (obj.type == YBMFNodeTypeNSArray || obj.type == YBMFNodeTypeNSMutableArray) { 260 | YBMFNode *child = obj.children[YBMFNodeArrayElementKey]; 261 | if (child && child.type == YBMFNodeTypeClass) { 262 | [self dfs_mergeWithCodeInFileH:codeInFileH codeInFileM:codeInFileM node:child]; 263 | } 264 | } 265 | }]; 266 | [codeInFileH appendString:[self.config.fileHHandler ybmf_codeInfoWithNode:node]]; 267 | [codeInFileH appendString:@"\n\n"]; 268 | [codeInFileM appendString:[self.config.fileMHandler ybmf_codeInfoWithNode:node]]; 269 | [codeInFileM appendString:@"\n\n"]; 270 | } 271 | 272 | #pragma mark - tool 273 | 274 | - (NSString *)allInfoFileH:(YBMFNode *)node { 275 | NSString *noteInFileH = [self.config.fileNoteHander ybmf_fileNoteWithFileName:node.className fileType:YBMFFileNoteTypeH]; 276 | NSString *importInfoInFileH = [self.config.fileHHandler ybmf_importInfoWithNode:node withoutProperty:NO]; 277 | NSString *codeInfoInFileH = [self.config.fileHHandler ybmf_codeInfoWithNode:node]; 278 | NSString *allInfoFileH = [NSString stringWithFormat: 279 | @"%@\n%@\n" 280 | "NS_ASSUME_NONNULL_BEGIN\n\n" 281 | "%@" 282 | "\nNS_ASSUME_NONNULL_END\n", noteInFileH, importInfoInFileH, codeInfoInFileH]; 283 | return allInfoFileH; 284 | } 285 | 286 | - (NSString *)allInfoFileM:(YBMFNode *)node { 287 | NSString *noteInFileM = [self.config.fileNoteHander ybmf_fileNoteWithFileName:node.className fileType:YBMFFileNoteTypeM]; 288 | NSString *importInfoInFileM = [self.config.fileMHandler ybmf_importInfoWithNode:node]; 289 | NSString *codeInfoInFileM = [self.config.fileMHandler ybmf_codeInfoWithNode:node]; 290 | NSString *allInfoFileM = [NSString stringWithFormat:@"%@\n%@\n%@", noteInFileM, importInfoInFileM, codeInfoInFileM]; 291 | return allInfoFileM; 292 | } 293 | 294 | @end 295 | -------------------------------------------------------------------------------- /YBModelFileDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /YBModelFileDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /YBModelFileDemo.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /YBModelFileDemo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /YBModelFileDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/18. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /YBModelFileDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/18. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /YBModelFileDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /YBModelFileDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /YBModelFileDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /YBModelFileDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /YBModelFileDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Model文件生成器 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /YBModelFileDemo/PrefixHeader.pch: -------------------------------------------------------------------------------- 1 | // 2 | // PrefixHeader.pch 3 | // ToolsDemoByYangBo 4 | // 5 | // Created by 杨波 on 17/3/3. 6 | // Copyright © 2017年 yangbo. All rights reserved. 7 | // 8 | 9 | #ifndef PrefixHeader_pch 10 | #define PrefixHeader_pch 11 | 12 | #import 13 | #import 14 | 15 | #endif /* PrefixHeader_pch */ 16 | -------------------------------------------------------------------------------- /YBModelFileDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/18. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /YBModelFileDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/18. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "YBModelFile.h" 11 | 12 | @interface ViewController () 13 | 14 | @end 15 | 16 | @implementation ViewController 17 | 18 | - (instancetype)init { 19 | self = [super init]; 20 | if (self) { 21 | 22 | /* 全局公用配置 (只需设置在使用工具之前就行了) */ 23 | 24 | //属性或方法是否空行 25 | // [YBMFConfig shareConfig].fileHHandler.ybmf_skipLine = YES; 26 | // [YBMFConfig shareConfig].fileMHandler.ybmf_skipLine = YES; 27 | //是否需要实现 NSCoding 或 NSCopying 协议 28 | // [YBMFConfig shareConfig].needCoding = NO; 29 | // [YBMFConfig shareConfig].needCopying = NO; 30 | //设置类名公用后缀 31 | // [YBMFConfig shareConfig].fileSuffix = @"File"; 32 | //设置忽略类型 33 | // [YBMFConfig shareConfig].ignoreType = YBMFIgnoreTypeAllDigital | YBMFIgnoreTypeMutable; 34 | //设置文件划分策略 35 | // [YBMFConfig shareConfig].filePartitionMode = YBMFFilePartitionModeApart; 36 | //设置工程用的字典转模型框架 37 | // [YBMFConfig shareConfig].framework = YBMFFrameworkMJ; 38 | } 39 | return self; 40 | } 41 | 42 | - (void)viewDidLoad { 43 | [super viewDidLoad]; 44 | 45 | //解析微博的json 46 | [YBModelFile createFileWithName:@"WBTrends" data:@"weibo_0"]; 47 | 48 | 49 | //解析微博的json (带独有配置) 50 | /* 51 | YBMFConfig *config = [YBMFConfig defaultConfig]; 52 | config.fileNoteHander.ybmf_developer = @"hahaha"; 53 | [YBModelFile createFileWithName:@"WBTrends" data:@"weibo_0" config:config]; 54 | */ 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /YBModelFileDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // YBModelFileDemo 4 | // 5 | // Created by 杨波 on 2019/3/18. 6 | // Copyright © 2019 杨波. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | --------------------------------------------------------------------------------