浅浅的解析---MJExtension

MJExtension.png

做一件事儿肯定是有原因,我来做这个事儿的原因,是因为我鹏哥思考需要在,路漫漫其修远兮,上下求索。

然后...鑫哥觉得,要成为大牛,首先要做的就是先跟大牛学习下,那么就抄一下大牛的代码吧...(我觉得很对)

一步一步走走看看,那么就先从我们最为常用的MJEX来入手,我也来copy一遍代码来试试

根据以前的样子,那么我先把目录写下来,然后进行一步一步一步的摩擦,且来看看👀👀

MJExtension

MJEX.png

引入头文件真的没什么可说的
MJExtension.h作为一个.h的头文件引入类,可谓是清新脱俗,简单明了 ...巴拉巴拉巴拉
然后下一步开始逐渐解析MJEX

MJExtensionConst

方法过期使用

#define MJExtensionDeprecated(instead) NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead)
这个方法在设计库或者sdk的时候会使用到,然后标注显示

删除横线.png

具体使用的是如下方法
@property(nonatomic, copy)NSString *gdtype __attribute__((deprecated("已过期, 用goodsclassifytype替换")));

构建错误

#define MJExtensionBuildError(clazz, msg) \
NSError *error = [NSError errorWithDomain:msg code:250 userInfo:nil]; \
[clazz setMj_error:error];
NSError类里面的方法使用.png

其中,自定义错误域对象CustomErrorDomain,通常用域名反写,也可以是任何其他字符串code错误标识, 系统的code一般都大于零,自定code可以用枚举(最好用负数, 但不是必须的)userInfo自定义错误信息,NSLocalizedDescriptionKey是NSError头文件中预定义的键,标识错误的本地化描述

可以通过NSError的localizedDescription方法获得对应的值信息
详细介绍NSError的可以查看iphone跬步之--错误信息 NSError

日志输出

这一块代码没什么可以讲解的,就是log的打印

#ifdef DEBUG
#define MJExtensionLog(...) NSLog(__VA_ARGS__)
#else
#define MJExtensionLog(...)
#endif

使用
#define NSLog(fmt, ...) NSLog((@"%s [Line: %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
这个打印,会打印出你的类名方法名和对应的行数[当做平时的一个小知识来记忆吧~]

剩下的这一堆是断言的使用

/**
 * 断言
 * @param condition   条件
 * @param returnValue 返回值
 */
#define MJExtensionAssertError(condition, returnValue, clazz, msg) \
[clazz setMj_error:nil]; \
if ((condition) == NO) { \
    MJExtensionBuildError(clazz, msg); \
    return returnValue;\
}

#define MJExtensionAssert2(condition, returnValue) \
if ((condition) == NO) return returnValue;

/**
 * 断言
 * @param condition   条件
 */
#define MJExtensionAssert(condition) MJExtensionAssert2(condition, )

/**
 * 断言
 * @param param         参数
 * @param returnValue   返回值
 */
#define MJExtensionAssertParamNotNil2(param, returnValue) \
MJExtensionAssert2((param) != nil, returnValue)

/**
 * 断言
 * @param param   参数
 */
#define MJExtensionAssertParamNotNil(param) MJExtensionAssertParamNotNil2(param, )```
>断言:NSAssert()是一个宏,用于开发阶段调试程序中的Bug,通过为NSAssert()传递条件表达式来断定是否属于Bug,满足条件返回真值,程序继续运行,如果返回假值,则抛出异常,并且可以自定义异常描述。
这里引用下别人对于[断言的介绍](http://www.jianshu.com/p/6e444981ab45)

MJEX将打印所有的属性使用宏定义在Const里面写出,为了可以在全局中方便的调用

/**

  • 打印所有的属性
    */

define MJLogAllIvars \

-(NSString *)description
{
return [self mj_keyValues].description;
}

define MJExtensionLogAllProperties MJLogAllIvars

直接调用`MJLogAllIvars `的宏定义就可以直接输出所有属性

类属性的使用 

/**

  • 类型(属性类型)
    */
    extern NSString *const MJPropertyTypeInt;
    extern NSString *const MJPropertyTypeShort;
    extern NSString *const MJPropertyTypeFloat;
    extern NSString *const MJPropertyTypeDouble;
    extern NSString *const MJPropertyTypeLong;
    extern NSString *const MJPropertyTypeLongLong;
    extern NSString *const MJPropertyTypeChar;
    extern NSString *const MJPropertyTypeBOOL1;
    extern NSString *const MJPropertyTypeBOOL2;
    extern NSString *const MJPropertyTypePointer;

extern NSString *const MJPropertyTypeIvar;
extern NSString *const MJPropertyTypeMethod;
extern NSString *const MJPropertyTypeBlock;
extern NSString *const MJPropertyTypeClass;
extern NSString *const MJPropertyTypeSEL;
extern NSString *const MJPropertyTypeId;

从这个类属性里面,我们可以清楚的了解到MJEX对于某些类的拓展使用

/**

  • 成员变量类型(属性类型)
    */
    NSString *const MJPropertyTypeInt = @"i";
    NSString *const MJPropertyTypeShort = @"s";
    NSString *const MJPropertyTypeFloat = @"f";
    NSString *const MJPropertyTypeDouble = @"d";
    NSString *const MJPropertyTypeLong = @"l";
    NSString *const MJPropertyTypeLongLong = @"q";
    NSString *const MJPropertyTypeChar = @"c";
    NSString *const MJPropertyTypeBOOL1 = @"c";
    NSString *const MJPropertyTypeBOOL2 = @"b";
    NSString const MJPropertyTypePointer = @"";

NSString *const MJPropertyTypeIvar = @"^{objc_ivar=}";
NSString *const MJPropertyTypeMethod = @"^{objc_method=}";
NSString *const MJPropertyTypeBlock = @"@?";
NSString *const MJPropertyTypeClass = @"#";
NSString *const MJPropertyTypeSEL = @":";
NSString *const MJPropertyTypeId = @"@";

【借鉴】对于.m里面的赋值,从而借鉴可以从编辑全局的某些text或者Toast的信息可以使用上方式作为统一的管理:
例如
.h
`extern NSString *const MJToast_Success;`
.m
`NSString *const MJToast_Success  = @"保存成功"`
从而在全局统一使用

##MJFoundation
继承自`@interface MJFoundation : NSObject`只用一个方法
`+ (BOOL)isClassFromFoundation:(Class)c;`
>MJ是这样注释的----
集合中没有NSObject,因为几乎所有的类都是继承自NSObject,具体是不是NSObject需要特殊判断

![使用NSSet将数据的不属于NSObj的类加入.png](http://upload-images.jianshu.io/upload_images/693139-25f36e7cfb54e302.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

>【注意】NSSet和NSMutableSet是无序的!!!!看准咯是无序的!因为它本身的排序是使用的哈希排序(划重点)
而且他是唯一的!!里面的每一个数据都是唯一的!!!!(划重点)
之前我遇到的问题也是如此,讨厌于双重for循环去去重,直接使用了NSMutableSet,但是没有注意到是无序的序列,对于需要排序的,建议写一个字段排序的方法,这里不再做赘述


##MJProperty -- 包装一个成员属性
关于如何包装一个成员属性呢,那么我们先看一下MJ如何去做的
`/** 成员属性 */
@property (nonatomic, assign) objc_property_t property;`
> objc_property_t 
···what is this?
[iOS反射机制: objc_property_t的使用](https://segmentfault.com/a/1190000004520289)
这为大哥写的蛮详细,这里做简略的介绍
 `/// An opaque type that represents an Objective-C declared property.
typedef struct objc_property *objc_property_t;`
apple将其称为一个隐藏的类型,OC中的一个声明属性。

>iOS属性反射:说白了,就是将两个对象的所有属性,用动态的方式取出来,并根据属性名,自动绑值。(注意:对象的类,如果是派生类,就得靠其他方式来实现了,因为得到不该基类的属性。)

常用的反射方式,有如下两种:


>2-从一个NSDictionary->自定义实体类(此方式最最常用,如网络Json数据会组成NSDictionary。sqlite查询数据,可以用第三方组件组成NSDictionary)
直接上码,(这里码在NSObject类别中)
获取对象所有属性:

我注意到MJEX使用了这样一个属性---[关联](http://blog.csdn.net/onlyou930/article/details/9299169)

![关联属性-MJEX.png](http://upload-images.jianshu.io/upload_images/693139-5f145a81a8f9ee75.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

这个类的核心代码如下,我么一段一段进行解析
// 通过字符串key创建对应的keys
```objective-c
 - (NSArray *)propertyKeysWithStringKey:(NSString *)stringKey
    {
        if (stringKey.length == 0) return nil;
        
        NSMutableArray *propertyKeys = [NSMutableArray array];
        // 如果有多级映射
        NSArray *oldKeys = [stringKey componentsSeparatedByString:@"."];
        
        for (NSString *oldKey in oldKeys) {
            NSUInteger start = [oldKey rangeOfString:@"["].location;
            if (start != NSNotFound) { // 有索引的key
                NSString *prefixKey = [oldKey substringToIndex:start];
                NSString *indexKey = prefixKey;
                if (prefixKey.length) {
                    MJPropertyKey *propertyKey = [[MJPropertyKey alloc] init];
                    propertyKey.name = prefixKey;
                    [propertyKeys addObject:propertyKey];
                    
                    indexKey = [oldKey stringByReplacingOccurrencesOfString:prefixKey withString:@""];
                }
                
                /** 解析索引 **/
                // 元素
                NSArray *cmps = [[indexKey stringByReplacingOccurrencesOfString:@"[" withString:@""] componentsSeparatedByString:@"]"];
                for (NSInteger i = 0; i<cmps.count - 1; i++) {
                    MJPropertyKey *subPropertyKey = [[MJPropertyKey alloc] init];
                    subPropertyKey.type = MJPropertyKeyTypeArray;
                    subPropertyKey.name = cmps[i];
                    [propertyKeys addObject:subPropertyKey];
                }
            } else { // 没有索引的key
                MJPropertyKey *propertyKey = [[MJPropertyKey alloc] init];
                propertyKey.name = oldKey;
                [propertyKeys addObject:propertyKey];
            }
        }
        
        return propertyKeys;
    }

采用多级映射的方式,将对应的关联key值进行

MJPropertyKey

MJPropertyType

NSObject+MJClass

NSObject+MJCoding

NSObject+MJKeyValue

NSObject+MJProperty

NSString+MJExtension

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,678评论 0 9
  • 你有没有一个无法靠近的人? 为了靠近他,你想尽办法,用尽心思,最后只得到一个过分热情的结论,你毫无反抗之力,也无从...
    花田夜语阅读 480评论 0 1
  • 你是不是经常在领导面前或者公众面前说话时有一种身体被扭曲,手舞足蹈,不知如何安放自己的双手,恨不得把自己双手砍掉的...
    小叮当在哪里阅读 997评论 0 1
  • 有人问:“我喜欢的女孩子,不理我了,本来她跟我无话不说的……算了,我也给不了她什么,还是放弃吧……我也累了,不打扰...
    司马香老师阅读 267评论 0 1