MJExtension common method

A, MJExtension third-party framework

We iOS development process, we often need to convert between the dictionary data (ie JSON data) and Model models, such as micro-blog network requests data returned, and so on, if we own all manual models to create and assign, Some are no technical content code, time consuming, and may also assign wrong, let us headache.

MJExtension framework is designed to solve this problem have third party open source libraries. The library is open before Chi Chuan instructor Li Mingjie blog written by the teacher, and now he himself out to do, and I see Li Mingjie iOS entry are learning teacher training video, he speaks very well, I like him, he can be considered my teacher, his work I still have to learn under.

It provides some of the following ways:

  1. Simple Dictionary -> Model
  2. JSON string -> model
  3. Complex dictionary -> model (model which contains the model)
  4. Complex dictionary -> model (model array property inside and filled with model)
  5. Complex dictionary -> model (key attribute names and model dictionary is not the same)
  6. Dictionary array -> Array model
  7. Models -> Dictionary
  8. Model array -> Array dictionary
  9. Dictionary -> CoreData model
  10. Archive and unarchived NSCoding
  11. Value filter dictionary

MJExtension framework is written using the mechanism when run Obj-C, and now iOS Swift development language to language development, I do not know whether Swift languages ​​also have this characteristic, the future of the framework will also develop in the Swift language rather not go know, but this framework is very lightweight, very suitable for junior developers to see its source code, there is a very big help for understanding the operation of Obj-C mechanism.

Two, Runtime runtime mechanism is simple to understand

Runtime is running short, it is that some mechanism when the system is running, the most important is the message mechanism.

OC similar function call message, is the dynamic calling procedure. At compile time and you can not really decide which function to call. It turns out that the compilation stage, OC can call any function, even if the function has not been achieved, as long as the error will not over-stated. The C language will give an error at compile time. You will only find the corresponding function to call when you actually run according to the name of the function.

For example, the following code will be converted at compile time:

/* OC方法调用 */
[obj makeTest];
/* 编译时Runtime会将上面的代码转为下面的消息发送 */
objc_msgSend(obj, @selector(makeText)); 

iOS top NSObject base class contains a pointer to a pointer isa objc_class structure:

@interface NSObject{
Class isa;
};
typedef struct objc_class *Class; struct objc_class { Class isa; // 指向metaclass,也就是静态的Class Class super_class ; // 指向其父类 const char *name ; // 类名 long version ; // 类的版本信息,初始化默认为0 /* 一些标识信息,如CLS_CLASS(0x1L)表示该类为普通class; CLS_META(0x2L)表示该类为metaclass */ long info; long instance_size ; // 该类的实例变量大小(包括从父类继承下来的实例变量 struct objc_ivar_list *ivars; // 用于存储每个成员变量的地址 /* 与info的一些标志位有关,如是普通class则存储对象方法,如是metaclass则存储类方法 */ struct objc_method_list **methodLists ; struct objc_cache *cache; // 指向最近使用的方法的指 针,用于提升效率; struct objc_protocol_list *protocols; // 存储该类 遵守的协议 }; 
 
1795722-93c68c68674d07ee.jpg

Call a procedure in objc_msgSend function:

  1. First, find the corresponding obj isa pointer by Class of obj.
  2. In the Class go to the cache function to find the corresponding method by SEL
  3. If the cache is not found, go look in methodLists
  4. If methodLists not found, the recursive lookup by entering superClass previous steps
  5. If the method is found, the method is added to the cache in order to facilitate the next search, and jump to the corresponding function through a function pointer method of execution.
  6. If you have been found NSObject not found, it will enter the message dynamic processes.

Dynamic message processing flow:

/* 1\. 时机处理之一,在这个方法中我们可以利用runtime的特性动态添加方法来处理 */
+ (BOOL)resolveInstanceMethod:(SEL)sel;
/* 2\. 时机处理之二,在这个方法中看代理能不能处理,如果代理对象能处理,则转接给代理对象 */
- (id)forwardingTargetForSelector:(SEL)aSelector;
/* 3\. 消息转发之一,该方法返回方法签名,如果返回nil,则转发流程终止,抛出异常 */ - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector; /* 4\. 消息转发之二,在该方法中我们可以对调用方法进行重定向 */ - (void)forwardInvocation:(NSInvocation *)anInvocation; 
 
1795722-008e4e09b0e93dd7.jpg

So we can use Runtime mechanism to dynamically add methods or class attributes:

/* 动态向一个类添加属性 */
class_addIvar(kclass, "expression", size, alignment, "*");
/* 动态向一个类添加方法 */
class_addMethod(kclass, @selector(setExpressionFormula:), (IMP)setExpressionFormula, "v@:@"); class_addMethod(kclass, @selector(getExpressionFormula), (IMP)getExpressionFormula, "@@:"); static void setExpressionFormula(id self, SEL cmd, id value){ NSLog(@"call setExpressionFormula"); } static id getExpressionFormula(id self, SEL cmd) { NSLog(@"call getExpressionFormula"); return nil; } 
  1. v represents the void, @ id represents the type: the type of representation SEL
  2. "V @: @": represents the return value is void, accepts an id type, a type SEL, a method of the type id
  3. "@@:": indicates the type of return value id, id accepts a parameter type and a method of the type SEL

Details Runtime runtime specific, here is not to go into detail, but simply to understand the next Runtime can be done dynamically add properties and methods to the class on the line.

Two, MJExtension use

Most of the methods MJExtension implementation are integrated into the classification without the use of a new class, you only need to include the header file MJExtension.h. MJExtension instructions on github has written very understand.

1. Simple Dictionary -> Model

User model class definition:

typedef enum {
    SexMale,
    SexFemale
} Sex;
@interface User : NSObject @property (copy, nonatomic) NSString *name;/* 姓名 */ @property (copy, nonatomic) NSString *icon;/* 头像 */ @property (assign, nonatomic) unsigned int age;/* 年龄 */ @property (copy, nonatomic) NSString *height;/* 身高 */ @property (strong, nonatomic) NSNumber *money;/* 资产 */ @property (assign, nonatomic) Sex sex;/* 性别 */ @property (assign, nonatomic, getter=isGay) BOOL gay;/* 是否是同性恋 */ @end 

Example:

NSDictionary *dict = @{
    @"name" : @"Jack",
    @"icon" : @"lufy.png",
    @"age" : @20, @"height" : @"1.55", @"money" : @100.9, @"sex" : @(SexFemale),/* 枚举需要使用NSNumber包装 */ @"gay" : @"NO" }; //字典转模型,使用的是mj_objectWithKeyValues:方法 User *user = [User mj_objectWithKeyValues:dict]; 

2. JSON string -> model

Example:

// 定义一个JSON字符串
NSString *jsonString = @"{\"name\":\"Jack\", \"icon\":\"lufy.png\", \"age\":20}";
// JSON字符串转模型
User *user = [User mj_objectWithKeyValues:jsonString];

3. complex dictionary -> model (model which contains the model)

Status model class definition:

@interface Status : NSObject
@property (copy, nonatomic) NSString *text; @property (strong, nonatomic) User *user;/* 其他模型类型 */ @property (strong, nonatomic) Status *retweetedStatus;/* 自我模型类型 */ @end 

Example:

NSDictionary *dict = @{
    @"text" : @"Agree!Nice weather!",
    @"user" : @{
        @"name" : @"Jack", @"icon" : @"lufy.png" }, @"retweetedStatus" : @{ @"text" : @"Nice weather!", @"user" : @{ @"name" : @"Rose", @"icon" : @"nami.png" } } }; //字典转模型,模型里面含有模型 Status *status = [Status mj_objectWithKeyValues:dict]; NSString *text = status.text; NSString *name = status.user.name; NSString *icon = status.user.icon; NSLog(@"text=%@, name=%@, icon=%@", text, name, icon); // text=Agree!Nice weather!, name=Jack, icon=lufy.png NSString *text2 = status.retweetedStatus.text; NSString *name2 = status.retweetedStatus.user.name; NSString *icon2 = status.retweetedStatus.user.icon; NSLog(@"text2=%@, name2=%@, icon2=%@", text2, name2, icon2); // text2=Nice weather!, name2=Rose, icon2=nami.png 

4. The complex dictionary -> model (model array property inside and filled with model)

Ad and StatusResult model class definition:

@interface Ad : NSObject
@property (copy, nonatomic) NSString *image; @property (copy, nonatomic) NSString *url; @end @interface StatusResult : NSObject /** 数组中存储模型Status类型数据 */ @property (strong, nonatomic) NSMutableArray *statuses; /** 数组中存储模型Ad类型数据 */ @property (strong, nonatomic) NSArray *ads; @property (strong, nonatomic) NSNumber *totalNumber; @end #import "MJExtension.h" /* 数组中存储模型数据,需要说明数组中存储的模型数据类型 */ @implementation StatusResult /* 实现该方法,说明数组中存储的模型数据类型 */ + (NSDictionary *)mj_ objectClassInArray{ return @{ @"statuses" : @"Status", @"ads" : @"Ad" }; } @end 

Example:

NSDictionary *dict = @{
    @"text" : @"Agree!Nice weather!",
    @"user" : @{
        @"name" : @"Jack", @"icon" : @"lufy.png" }, @"retweetedStatus" : @{ @"text" : @"Nice weather!", @"user" : @{ @"name" : @"Rose", @"icon" : @"nami.png" } } }; //字典转模型,模型里面含有模型 Status *status = [Status mj_objectWithKeyValues:dict]; NSString *text = status.text; NSString *name = status.user.name; NSString *icon = status.user.icon; NSLog(@"text=%@, name=%@, icon=%@", text, name, icon); // text=Agree!Nice weather!, name=Jack, icon=lufy.png NSString *text2 = status.retweetedStatus.text; NSString *name2 = status.retweetedStatus.user.name; NSString *icon2 = status.retweetedStatus.user.icon; NSLog(@"text2=%@, name2=%@, icon2=%@", text2, name2, icon2); // text2=Nice weather!, name2=Rose, icon2=nami.png 

5. complicated Dictionary -> model (key attribute names and model dictionary is not the same)

Bag model classes and Student definitions:

@interface Bag : NSObject
@property (copy, nonatomic) NSString *name; @property (assign, nonatomic) double price; @end @interface Student : NSObject @property (copy, nonatomic) NSString *ID; @property (copy, nonatomic) NSString *desc; @property (copy, nonatomic) NSString *nowName; @property (copy, nonatomic) NSString *oldName; @property (copy, nonatomic) NSString *nameChangedTime; @property (strong, nonatomic) Bag *bag; @end #import "MJExtension.h" @implementation /* 设置模型属性名和字典key之间的映射关系 */ + (NSDictionary *)mj_replacedKeyFromPropertyName{ /* 返回的字典,key为模型属性名,value为转化的字典的多级key */ return @{ @"ID" : @"id", @"desc" : @"desciption", @"oldName" : @"name.oldName", @"nowName" : @"name.newName", @"nameChangedTime" : @"name.info[1].nameChangedTime", @"bag" : @"other.bag" }; } @end 

Example:

NSDictionary *dict = @{
    @"id" : @"20",
    @"desciption" : @"kids", @"name" : @{ @"newName" : @"lufy", @"oldName" : @"kitty", @"info" : @[ @"test-data", @{ @"nameChangedTime" : @"2013-08" } ] }, @"other" : @{ @"bag" : @{ @"name" : @"a red bag", @"price" : @100.7 } } }; //字典转模型,支持多级映射 Student *stu = [Student mj_objectWithKeyValues:dict]; //打印 NSLog(@"ID=%@, desc=%@, oldName=%@, nowName=%@, nameChangedTime=%@", stu.ID, stu.desc, stu.oldName, stu.nowName, stu.nameChangedTime); // ID=20, desc=kids, oldName=kitty, nowName=lufy, nameChangedTime=2013-08 NSLog(@"bagName=%@, bagPrice=%f", stu.bag.name, stu.bag.price); // bagName=a red bag, bagPrice=100.700000 

6. Array Dictionary -> Model array

Example:

NSArray *dictArray = @[
                         @{
                             @"name" : @"Jack",
                             @"icon" : @"lufy.png" }, @{ @"name" : @"Rose", @"icon" : @"nami.png" } ]; //字典数组转模型数组,使用的是mj_objectArrayWithKeyValuesArray:方法 NSArray *userArray = [User mj_objectArrayWithKeyValuesArray:dictArray]; //打印 for (User *user in userArray) { NSLog(@"name=%@, icon=%@", user.name, user.icon); } // name=Jack, icon=lufy.png // name=Rose, icon=nami.png 

7. Models -> Dictionary

Example:

//创建一个模型对象
User *user = [[User alloc] init];
user.name = @"Jack";
user.icon = @"lufy.png";
Status *status = [[Status alloc] init];
status.user = user;
status.text = @"Nice mood!";
//模型转字典,使用的是mj_keyValues属性 NSDictionary *statusDict = status.mj_keyValues; NSLog(@"%@", statusDict); /* { text = "Nice mood!"; user = { icon = "lufy.png"; name = Jack; }; } */ 

8. Model Array -> Array dictionary

Example:

//创建模型数组
User *user1 = [[User alloc] init];
user1.name = @"Jack";
user1.icon = @"lufy.png";
User *user2 = [[User alloc] init];
user2.name = @"Rose";
user2.icon = @"nami.png"; NSArray *userArray = @[user1, user2]; //模型数组转字典数组,使用的是mj_keyValuesArrayWithObjectArray:方法 NSArray *dictArray = [User mj_keyValuesArrayWithObjectArray:userArray]; NSLog(@"%@", dictArray); /* ( { icon = "lufy.png"; name = Jack; }, { icon = "nami.png"; name = Rose; } ) */ 

9. Dictionary -> CoreData model

Example:

NSDictionary *dict = @{
                         @"name" : @"Jack",
                         @"icon" : @"lufy.png", @"age" : @20, @"height" : @1.55, @"money" : @"100.9", @"sex" : @(SexFemale), @"gay" : @"true" }; //字典转为CoreData模型 NSManagedObjectContext *context = nil; User *user = [User mj_objectWithKeyValues:dict context:context]; [context save:nil]; 

10. Filing and unarchives NSCoding

Adding to achieve model class Bag

@interface Bag : NSObject <NSCoding> @property (copy, nonatomic) NSString *name; @property (assign, nonatomic) double price; @end #import "MJExtension.h" @implementation Bag //添加了下面的宏定义 MJExtensionCodingImplementation /* 实现下面的方法,说明哪些属性不需要归档和解档 */ + (NSArray *)mj_ignoredCodingPropertyNames{ return @[@"name"]; } @end 

Example:

//创建模型
Bag *bag = [[Bag alloc] init];
bag.name = @"Red bag";
bag.price = 200.8;
//获取归档路径
NSString *file = [NSHomeDirectory() stringByAppendingPathComponent:@"Desktop/bag.data"]; //归档 [NSKeyedArchiver archiveRootObject:bag toFile:file]; //解档 Bag *decodedBag = [NSKeyedUnarchiver unarchiveObjectWithFile:file]; NSLog(@"name=%@, price=%f", decodedBag.name, decodedBag.price); // name=(null), price=200.800000 

11. The filter value of the dictionary

Book achieve model class:

@interface Book: NSObject
@property (copy, nonatomic) NSString *name; @property (strong, nonatomic) NSDate *publishedTime; @end #import "MJExtension.h" @implementation Book /* 转化过程中对字典的值进行过滤和进一步转化 */ - (id)mj_newValueFromOldValue:(id)oldValue property:(MJProperty *)property { if ([property.name isEqualToString:@"publisher"]) { if (oldValue == nil) { return @""; } } else if (property.type.typeClass == [NSDate class]) { NSDateFormatter *fmt = [[NSDateFormatter alloc] init]; fmt.dateFormat = @"yyyy-MM-dd"; return [fmt dateFromString:oldValue]; } return oldValue; } @end 

Example:

NSDictionary *dict = @{
                       @"name" : @"5分钟突破iOS开发",
                       @"publishedTime" : @"2011-09-10" }; //字典转模型,过滤name为nil的情况,把NSString转为NSDate Book *book = [Book mj_objectWithKeyValues:dict]; //打印 NSLog(@"name=%@, publishedTime=%@", book.name, book.publishedTime); 

Github point MJExtension address here: CoderMJLee / MJExtension



Author: Baylor Classic
link: https: //www.jianshu.com/p/53ff148c6670
Source: Jane book
Jane book copyright reserved by the authors, are reproduced in any form, please contact the author to obtain authorization and indicate the source.

Guess you like

Origin www.cnblogs.com/Acee/p/10930008.html