MJExtension的用法优化

关于MJExtension的基本用法和高级用法大家都熟透在心了,很多文章介绍MJExtension怎么用,介绍MJExtension的高级API,泛滥了哦!一发不可收拾!所以此文主要介绍优化。

  • 本人找了好多文章,没有谈及MJExtension的优化的。MJ老师也在github上MJExtension的demo里做了用法引导,大家都用的很happy!
    但是我有一个疑问,这个疑问大部分用MJExtension的开发者应该都遇到过,就是关于每个model的配置代码应该写在哪里?!可能是因为MJExtension官方已经给了引导用法,大部分开发者直接照搬了MJExtension的demo中的用法。关于model需要配置的东东这里举个例子,比如后台返回的json里面含有id、void、description、new等OC关键字的时候,需要进行model属性的key的替换,意思就是用ID当key去map映射json中的id这个key,就可以用这个方法mj_setupReplacedKeyFromPropertyName进行配置,或者在Student类的.m中重写+mj_replacedKeyFromPropertyName这个方法,代码如下:
// How to map
[Student mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
    return @{
               @"ID" : @"id",
               @"desc" : @"desciption"
           };
}];
// Equals: Student.m implements +mj_replacedKeyFromPropertyName method.
  • 还有一个比较蛋疼的问题,MJExtension也可以方便的设置,就是后台返回的数据中表示一个对象的其中的一个key不固定,举个例子,老师的id这个key,其实表示的意义是一样的,就是老师的编号id,但是由于后台开发人员比较多,没有互相交流和查看对方的代码,导致A接口返回的key是id,B接口tid,C接口ID,D接口Id,E接口iD。这就很尴尬了,本人真实遇到过,想让后台改过来,但是呢?他们说这样改的工作量相当相当大……….,此处省略一万字

那么解决办法就是这样的,我model中用teacherId这个key去map后台所有可能的key

[MJStudent mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
            return @{@"teacherId" : @[@"id", @"tid",@"ID",@"iD",@"Id"]};
        }];
  • 最后还有一个需要设置的项,就是model中含有数组,这个数组为一个model,下面是MJ老师给的例子

Model contains model-array【模型中有个数组属性,数组里面又要装着其他模型】

@interface Ad : NSObject
@property (copy, nonatomic) NSString *image;
@property (copy, nonatomic) NSString *url;
@end

@interface StatusResult : NSObject
/** Contatins status model */
@property (strong, nonatomic) NSMutableArray *statuses;
/** Contatins ad model */
@property (strong, nonatomic) NSArray *ads;
@property (strong, nonatomic) NSNumber *totalNumber;
@end

/***********************************************/

// Tell MJExtension what type model will be contained in statuses and ads.
[StatusResult mj_setupObjectClassInArray:^NSDictionary *{
    return @{
               @"statuses" : @"Status",
               // @"statuses" : [Status class],
               @"ads" : @"Ad"
               // @"ads" : [Ad class]
           };
}];
// Equals: StatusResult.m implements +mj_objectClassInArray method.

NSDictionary *dict = @{
    @"statuses" : @[
                      @{
                          @"text" : @"Nice weather!",
                          @"user" : @{
                              @"name" : @"Rose",
                              @"icon" : @"nami.png"
                          }
                      },
                      @{
                          @"text" : @"Go camping tomorrow!",
                          @"user" : @{
                              @"name" : @"Jack",
                              @"icon" : @"lufy.png"
                          }
                      }
                  ],
    @"ads" : @[
                 @{
                     @"image" : @"ad01.png",
                     @"url" : @"http://www.ad01.com"
                 },
                 @{
                     @"image" : @"ad02.png",
                     @"url" : @"http://www.ad02.com"
                 }
             ],
    @"totalNumber" : @"2014"
};

// JSON -> StatusResult
StatusResult *result = [StatusResult mj_objectWithKeyValues:dict];

NSLog(@"totalNumber=%@", result.totalNumber);
// totalNumber=2014

// Printing
for (Status *status in result.statuses) {
    NSString *text = status.text;
    NSString *name = status.user.name;
    NSString *icon = status.user.icon;
    NSLog(@"text=%@, name=%@, icon=%@", text, name, icon);
}
// text=Nice weather!, name=Rose, icon=nami.png
// text=Go camping tomorrow!, name=Jack, icon=lufy.png

// Printing
for (Ad *ad in result.ads) {
    NSLog(@"image=%@, url=%@", ad.image, ad.url);
}
// image=ad01.png, url=http://www.ad01.com
// image=ad02.png, url=http://www.ad02.com
  • 其中设置的关键代码是这句
[StatusResult mj_setupObjectClassInArray:^NSDictionary *{
    return @{
               @"statuses" : @"Status",
               // @"statuses" : [Status class],
               @"ads" : @"Ad"
               // @"ads" : [Ad class]
           };
}];
// Equals: StatusResult.m implements +mj_objectClassInArray method.
  • 所有以上举的例子都有设置(配置)这些代码,开发中你写在哪里了呢?直接写在VC里面?写在model类的.m实现文件里面?还是用了MJ老师的MJExtensionConfig类,一股脑全部放到MJExtensionConfig的.m文件里面,而且是写在MJExtensionConfig.m的+load方法里面。

  • 我个人觉得都不是最优的方案,经过我个人的研究,经历和尝试了下面几种方案如下,欢迎大家留言批评指正

方案一、

  • 这些配置代码写VC里面显然不对,model都是开发组的成员可复用的类,一个model类可能出现在n多个VC里面,那么如果我的一个model被我同事拿去用,他明显要在VC里面写这些配置代码,事实证明的确如此,他的确是写了一遍,产生了大量的垃圾代码。也不符合封装的逻辑,他错了,我也错了,因为我没封装好给别人直接使用。

方案二、

  • 在每个model的.m中重写方法,返回要配置的东东。这样再也不怕其他同事用你的model了,因为你都配置好了,他直接用就可以了,垃圾代码也少了,貌似是最优的,也符合封装的概念,但是,但是,但是,我发现重写的这些方法会反复调用,次数非常多,违背了初衷,本来设置的东东,一次设置,终身使用才行啊,尼玛一个json转model的解析过程调用n多次这个方法,不合理啊。到这里我也否认了这个方案。

方案三、

  • 既然方案一和方案二都不好,我就直接下载MJ老是的Demo,看MJ老师是怎么用的,结果眼前一亮,MJ老师果然是高,实在是高,他直接建立一个类MJExtensionConfig,然后把项目中所有的model的配置都放到了MJExtensionConfig的.m中的+load方法中,而且标明了这样的话,copy部分贴在下面方便查看。
#import "MJExtensionConfig.h"
#import "MJExtension.h"
#import "MJBag.h"
#import "MJUser.h"
#import "MJStatusResult.h"
#import "MJStudent.h"
#import "MJDog.h"
#import "MJBook.h"

@implementation MJExtensionConfig
/**
 *  这个方法会在MJExtensionConfig加载进内存时调用一次
 */
+ (void)load
{
#pragma mark 如果使用NSObject来调用这些方法,代表所有继承自NSObject的类都会生效
#pragma mark NSObject中的ID属性对应着字典中的id
    [NSObject mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
        return @{
                 @"ID" : @"id"
                 };
    }];



#pragma mark MJUser类的只有name、icon属性参与字典转模型
//    [MJUser mj_setupAllowedPropertyNames:^NSArray *{
//        return @[@"name", @"icon"];
//    }];
    // 相当于在MJUser.m中实现了+(NSArray *)mj_allowedPropertyNames方法

#pragma mark MJBag类中的name属性不参与归档
    [MJBag mj_setupIgnoredCodingPropertyNames:^NSArray *{
        return @[@"name"];
    }];
    // 相当于在MJBag.m中实现了+(NSArray *)mj_ignoredCodingPropertyNames方法

#pragma mark MJBag类中只有price属性参与归档
//    [MJBag mj_setupAllowedCodingPropertyNames:^NSArray *{
//        return @[@"price"];
//    }];
    // 相当于在MJBag.m中实现了+(NSArray *)mj_allowedCodingPropertyNames方法
  • 大家都知道+load方法在开发者不主动调用的情况下,如果你实现了load方法,那么只会在APP启动应用的时候调用一次,而且是在main函数被调用之前调用,算是比较早调用的func,load会把项目中所有的类都加载load一遍,load方法貌似可以进行项目中model类的配置,好像是再合适不过的了。但是我否定了方案三、也就是MJ老师的方案或者说是引导用法。为什么呢?load方法会拖慢程序启动时间,写demo可以,就如MJ老师的demo,但是写项目不可以,他会拖慢启动时间,这个是我所不能忍受的,另外一个不好之处就是MJExtensionConfig文件中要import项目中大部分需要设置model参数的类文件,这样不太好,项目越来越大,MJExtensionConfig中导入的头文件越来越多。 啊啊啊,我受不了。推荐一个cocoaChina的文章《iOS APP启动优化》http://www.cocoachina.com/ios/20170731/20071.html 摘抄一部分相关内容如下:优化方案
    main()调用之前加载过程,优化内容
    减少framework引用删除无用类,无用函数减少+load 函数使用

方案四、

  • 方案四是我个人开发中研究出的一个方案,是最优的方案。其实很简单,就是放到每个model类的.m中的+initialize方法中。为啥最优,为啥你要否定MJ的方案,解释如下,
    • 1、因为写在每个类的.m中,符合封装的概念,其他的同事直接用我的model类,不用管配置,每个model类管理自己的配置,算是比较合理的,如果有一天不需要这个类了,直接删除,VC里面相应的改动比较少,也体现了整体的概念。
    • 2、+initialize和+load方法有不同,initialize方法不会在程序启动的时候调用,而且有lazy懒加载的感觉, initialize方法相关要点

initialize的自然调用是在第一次主动使用当前类的时候(lazy,这一点和Java类的“clinit”的很像)。在initialize方法收到调用时,运行环境基本健全。initialize的运行过程中是能保证线程安全的。和load不同,即使子类不实现initialize方法,会把父类的实现继承过来调用一遍。注意的是在此之前,父类的方法已经被执行过一次了,同样不需要super调用。由于initialize的这些特点,使得其应用比load要略微广泛一些。可用来做一些初始化工作,或者单例模式的一种实现方案。

  • initialize的这些特点决定了方案四是目前最优的方案,不会拖慢启动时间,懒加载的模式会在我们第一次使用model类的时候,设置一次,使用则设置,不使用则不设置,一旦设置,对于APP这次启动而言,相关设置终身有效。如果是model中有继承关系,则在基类里面配置,因为initialize和load不同,即使子类不实现initialize方法,会把父类的实现继承过来调用一遍。注意的是在此之前,父类的方法已经被执行过一次了,注意initialize和load不要调用super哦!MJ老师的MJExtensionConfig这个方案,如果大家用了,其实很不方便,如果需要改动,那么就要去到这个MJExtensionConfig里面找你的model,然后改动(删、添加等),还有就是如果同事想看你的model的配置,找不到,因为可能他不知道有这个MJExtensionConfig文件,但是,如果你直接写在model的.m中,那么同事也很方便查看你的代码。还有就是可能你的同事添加了相同model的配置代码到MJExtensionConfig文件中,不会报错(写.m中的initialize不会产生垃圾代码,重复func会报错),产生垃圾代码,当然这个情况比较少,也是因为那个开发者不长眼。哈哈哈!本人已经这样使用,效果非常好,如果你的项目中使用了MJExtension我想你是时候优化一下了。
    参考文章《NSObject的load和initialize方法》http://www.cocoachina.com/ios/20150104/10826.html
    原文地址:http://blog.csdn.net/wenmingzheng/article/details/77610196
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容