淺淺的解析---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.lxweimin.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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 轉至元數據結尾創建: 董瀟偉,最新修改于: 十二月 23, 2016 轉至元數據起始第一章:isa和Class一....
    40c0490e5268閱讀 1,776評論 0 9
  • 你有沒有一個無法靠近的人? 為了靠近他,你想盡辦法,用盡心思,最后只得到一個過分熱情的結論,你毫無反抗之力,也無從...
    花田夜語閱讀 519評論 0 1
  • 你是不是經常在領導面前或者公眾面前說話時有一種身體被扭曲,手舞足蹈,不知如何安放自己的雙手,恨不得把自己雙手砍掉的...
    小叮當在哪里閱讀 1,052評論 0 1
  • 有人問:“我喜歡的女孩子,不理我了,本來她跟我無話不說的……算了,我也給不了她什么,還是放棄吧……我也累了,不打擾...
    司馬香老師閱讀 293評論 0 1