做一件事兒肯定是有原因,我來做這個事兒的原因,是因為我鵬哥思考需要在,路漫漫其修遠兮,上下求索。
然后...鑫哥覺得,要成為大牛,首先要做的就是先跟大牛學習下,那么就抄一下大牛的代碼吧...(我覺得很對)
一步一步走走看看,那么就先從我們最為常用的MJEX來入手,我也來copy一遍代碼來試試
根據以前的樣子,那么我先把目錄寫下來,然后進行一步一步一步的摩擦,且來看看????
MJExtension
引入頭文件真的沒什么可說的
MJExtension.h作為一個.h的頭文件引入類,可謂是清新脫俗,簡單明了 ...巴拉巴拉巴拉
然后下一步開始逐漸解析MJEX
MJExtensionConst
方法過期使用
#define MJExtensionDeprecated(instead) NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead)
這個方法在設計庫或者sdk的時候會使用到,然后標注顯示
具體使用的是如下方法
@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];
其中,自定義錯誤域對象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和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)

這個類的核心代碼如下,我么一段一段進行解析
// 通過字符串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值進行